mtp-0.0.3+14.04.20140409/0000755000015301777760000000000012321134053014705 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/tests/0000755000015301777760000000000012321134053016047 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/tests/TestMtpServer.cpp0000644000015301777760000000415212321133655021353 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include "mtp.h" #include "MockMtpDatabase.h" #include "MtpServer.h" #include "MtpStorage.h" using namespace android; BOOST_AUTO_TEST_CASE(ServerConstructor) { MtpDatabase *db = new MockMtpDatabase (); MtpServer *server = new MtpServer (0, db, false, 0, 0, 0); BOOST_CHECK(server); } BOOST_AUTO_TEST_CASE(ServerAddGetStorage) { MtpDatabase *db = new MockMtpDatabase (); MtpServer *server = new MtpServer (0, db, false, 0, 0, 0); MtpStorage *storage = new MtpStorage (666, "/tmp", "Test storage", 0, false, 64); server->addStorage(storage); BOOST_CHECK(server->getStorage(666) != NULL); } BOOST_AUTO_TEST_CASE(ServerGetStorageNull) { MtpDatabase *db = new MockMtpDatabase (); MtpServer *server = new MtpServer (0, db, false, 0, 0, 0); BOOST_CHECK(server->getStorage(666) == NULL); } BOOST_AUTO_TEST_CASE(ServerHasStorageTrue) { MtpDatabase *db = new MockMtpDatabase (); MtpServer *server = new MtpServer (0, db, false, 0, 0, 0); MtpStorage *storage = new MtpStorage (666, "/tmp", "Test storage", 0, false, 64); server->addStorage(storage); BOOST_CHECK(server->hasStorage(666)); } BOOST_AUTO_TEST_CASE(ServerHasStorageFalse) { MtpDatabase *db = new MockMtpDatabase (); MtpServer *server = new MtpServer (0, db, false, 0, 0, 0); BOOST_CHECK(server->hasStorage(667) == false); } mtp-0.0.3+14.04.20140409/tests/TestMtpPacket.cpp0000644000015301777760000000251712321133655021317 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include "mtp.h" #include "MtpPacket.h" using namespace android; BOOST_AUTO_TEST_CASE(Packet) { MtpPacket *p = new MtpPacket (4); BOOST_REQUIRE(p); } BOOST_AUTO_TEST_CASE(PacketReset) { MtpPacket *p = new MtpPacket (MTP_CONTAINER_PARAMETER_OFFSET + 4); uint32_t value = UINT32_MAX; uint32_t result; BOOST_REQUIRE(p); p->setParameter(1, value); result = p->getParameter(1); BOOST_CHECK_EQUAL (value, result); p->reset(); result = p->getParameter(1); BOOST_CHECK (value != result); BOOST_CHECK (result == 0); } mtp-0.0.3+14.04.20140409/tests/TestMtpDebug.cpp0000644000015301777760000000314512321133655021134 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include "mtp.h" #include "MtpDebug.h" using namespace android; BOOST_AUTO_TEST_CASE(DebugGetOperationCodeName) { BOOST_CHECK_EQUAL( MtpDebug::getOperationCodeName(MTP_OPERATION_GET_DEVICE_INFO), "MTP_OPERATION_GET_DEVICE_INFO" ); } BOOST_AUTO_TEST_CASE(DebugGetFormatCodeName) { BOOST_CHECK_EQUAL( MtpDebug::getFormatCodeName(MTP_FORMAT_PNG), "MTP_FORMAT_PNG" ); } BOOST_AUTO_TEST_CASE(DebugGetObjectPropCodeName) { BOOST_CHECK_EQUAL( MtpDebug::getObjectPropCodeName(MTP_PROPERTY_STORAGE_ID), "MTP_PROPERTY_STORAGE_ID" ); } BOOST_AUTO_TEST_CASE(DebugGetDevicePropCodeName) { BOOST_CHECK_EQUAL( MtpDebug::getDevicePropCodeName(MTP_DEVICE_PROPERTY_BATTERY_LEVEL), "MTP_DEVICE_PROPERTY_BATTERY_LEVEL" ); } BOOST_AUTO_TEST_CASE(DebugGetCodeNameUnknown) { BOOST_CHECK_EQUAL( MtpDebug::getOperationCodeName (1), "UNKNOWN"); } mtp-0.0.3+14.04.20140409/tests/MockMtpDatabase.h0000644000015301777760000002575412321133675021245 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef STUB_MOCK_MTP_DATABASE_H_ #define STUB_MOCK_MTP_DATABASE_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { class MockMtpDatabase : public android::MtpDatabase { private: struct DbEntry { MtpStorageID storage_id; std::string object_name; MtpObjectFormat object_format; MtpObjectHandle parent; size_t object_size; std::string display_name; std::string path; }; uint32_t counter; std::map db; public: MockMtpDatabase() : counter(1) { DbEntry entry; db = std::map(); entry.storage_id = 666; entry.object_name = std::string("Test Object"); entry.object_format = MTP_FORMAT_PNG; entry.parent = MTP_PARENT_ROOT; entry.object_size = 666; entry.display_name = std::string("Test Object"); entry.path = std::string("TestObject"); db.insert( std::pair(counter, entry) ); } virtual ~MockMtpDatabase() {} virtual MtpObjectHandle beginSendObject( const MtpString& path, MtpObjectFormat format, MtpObjectHandle parent, MtpStorageID storage, uint64_t size, time_t modified) { return 1; } virtual void endSendObject( const MtpString& path, MtpObjectHandle handle, MtpObjectFormat format, bool succeeded) { std::cout << __PRETTY_FUNCTION__ << ": " << path << std::endl; if (!succeeded) { db.erase(handle); } } virtual MtpObjectHandleList* getObjectList( MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { MtpObjectHandleList* list = nullptr; if (db.empty()) { list = new MtpObjectHandleList(); } else { std::vector keys; keys.push_back(1); list = new MtpObjectHandleList(keys); } return list; } virtual int getNumObjects( MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { return db.size(); } virtual MtpObjectFormatList* getSupportedPlaybackFormats() { std::cout << __PRETTY_FUNCTION__ << std::endl; static const MtpObjectFormatList list = {MTP_FORMAT_PNG}; return new MtpObjectFormatList{list}; } virtual MtpObjectFormatList* getSupportedCaptureFormats() { std::cout << __PRETTY_FUNCTION__ << std::endl; static const MtpObjectFormatList list = {MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG}; return new MtpObjectFormatList{list}; } virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format) { std::cout << __PRETTY_FUNCTION__ << std::endl; static const MtpObjectPropertyList list = { MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_IMAGE_BIT_DEPTH, MTP_PROPERTY_DISPLAY_NAME }; return new MtpObjectPropertyList{list}; } virtual MtpDevicePropertyList* getSupportedDeviceProperties() { std::cout << __PRETTY_FUNCTION__ << std::endl; static const MtpDevicePropertyList list = { MTP_DEVICE_PROPERTY_UNDEFINED }; return new MtpDevicePropertyList{list}; } virtual MtpResponseCode getObjectPropertyValue( MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { std::cout << __PRETTY_FUNCTION__ << std::endl; switch(property) { case MTP_PROPERTY_STORAGE_ID: packet.putUInt32(db.at(handle).storage_id); break; case MTP_PROPERTY_PARENT_OBJECT: packet.putUInt32(db.at(handle).parent); break; case MTP_PROPERTY_OBJECT_FORMAT: packet.putUInt32(db.at(handle).object_format); break; case MTP_PROPERTY_OBJECT_SIZE: packet.putUInt32(db.at(handle).object_size); break; case MTP_PROPERTY_DISPLAY_NAME: packet.putString(db.at(handle).display_name.c_str()); break; default: return MTP_RESPONSE_GENERAL_ERROR; break; } return MTP_RESPONSE_OK; } virtual MtpResponseCode setObjectPropertyValue( MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode getDevicePropertyValue( MtpDeviceProperty property, MtpDataPacket& packet) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_GENERAL_ERROR; } virtual MtpResponseCode setDevicePropertyValue( MtpDeviceProperty property, MtpDataPacket& packet) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode resetDeviceProperty( MtpDeviceProperty property) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode getObjectPropertyList( MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode getObjectInfo( MtpObjectHandle handle, MtpObjectInfo& info) { std::cout << __PRETTY_FUNCTION__ << std::endl; info.mHandle = handle; info.mStorageID = db.at(handle).storage_id; info.mFormat = db.at(handle).object_format; info.mProtectionStatus = 0x0; info.mCompressedSize = 0; info.mThumbFormat = db.at(handle).object_format; info.mThumbCompressedSize = 20*20*4; info.mThumbPixWidth = 20; info.mThumbPixHeight =20; info.mImagePixWidth = 20; info.mImagePixHeight = 20; info.mImagePixDepth = 4; info.mParent = db.at(handle).parent; info.mAssociationType = 0; info.mAssociationDesc = 0; info.mSequenceNumber = 0; info.mName = ::strdup(db.at(handle).object_name.c_str()); info.mDateCreated = 0; info.mDateModified = 0; info.mKeywords = ::strdup("test"); return MTP_RESPONSE_OK; } virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) { void* result; outThumbSize = 0; memset(result, 0, outThumbSize); return result; } virtual MtpResponseCode getObjectFilePath( MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) { DbEntry entry = db.at(handle); std::cout << __PRETTY_FUNCTION__ << std::endl; outFilePath = std::string(entry.path); outFileLength = entry.object_size; outFormat = entry.object_format; return MTP_RESPONSE_OK; } virtual MtpResponseCode deleteFile(MtpObjectHandle handle) { size_t orig_size = db.size(); size_t new_size; std::cout << __PRETTY_FUNCTION__ << std::endl; new_size = db.erase(handle); if (orig_size > new_size) { BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).parent == handle) db.erase(i); } return MTP_RESPONSE_OK; } else return MTP_RESPONSE_GENERAL_ERROR; } virtual MtpResponseCode moveFile(MtpObjectHandle handle, MtpObjectHandle new_parent) { std::cout << __PRETTY_FUNCTION__ << std::endl; db.at(handle).parent = new_parent; return MTP_RESPONSE_OK; } virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle) { std::cout << __PRETTY_FUNCTION__ << std::endl; return nullptr; } virtual MtpResponseCode setObjectReferences( MtpObjectHandle handle, MtpObjectHandleList* references) { std::cout << __PRETTY_FUNCTION__ << std::endl; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpProperty* getObjectPropertyDesc( MtpObjectProperty property, MtpObjectFormat format) { std::cout << __PRETTY_FUNCTION__ << std::endl; MtpProperty* result = nullptr; switch(property) { case MTP_PROPERTY_STORAGE_ID: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_OBJECT_FORMAT: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_OBJECT_SIZE: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_WIDTH: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_HEIGHT: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_IMAGE_BIT_DEPTH: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_DISPLAY_NAME: result = new MtpProperty(property, MTP_TYPE_STR); break; default: break; } return result; } virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) { std::cout << __PRETTY_FUNCTION__ << std::endl; return new MtpProperty(MTP_DEVICE_PROPERTY_UNDEFINED, MTP_TYPE_UNDEFINED); } virtual void sessionStarted(MtpServer* server) { std::cout << __PRETTY_FUNCTION__ << std::endl; } virtual void sessionEnded() { std::cout << __PRETTY_FUNCTION__ << std::endl; } }; } #endif // STUB_MOCK_MTP_DATABASE_H_ mtp-0.0.3+14.04.20140409/tests/CMakeLists.txt0000644000015301777760000000262512321133655020623 0ustar pbusernogroup00000000000000 # MtpUtils add_executable( test-utils TestMtpUtils.cpp ) target_link_libraries( test-utils mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-utils test-utils) # MtpDebug add_executable( test-debug TestMtpDebug.cpp ) target_link_libraries( test-debug mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-debug test-debug) # MtpPacket add_executable( test-packet TestMtpPacket.cpp ) target_link_libraries( test-packet mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-packet test-packet) # MtpProperty add_executable( test-property TestMtpProperty.cpp ) target_link_libraries( test-property mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-property test-property) # MtpStorage add_executable( test-storage TestMtpStorage.cpp ) target_link_libraries( test-storage mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-storage test-storage) # MtpServer add_executable( test-server TestMtpServer.cpp ) target_link_libraries( test-server mtpserver usbhost ${Boost_LIBRARIES} ${Boost_unit_test_framework_LIBRARIES} ) add_test(test-server test-server) mtp-0.0.3+14.04.20140409/tests/TestMtpProperty.cpp0000644000015301777760000000564412321133655021740 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include "mtp.h" #include "MtpProperty.h" #include "MtpStringBuffer.h" using namespace android; BOOST_AUTO_TEST_CASE(PropertyConstructorString) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_NAME, MTP_TYPE_STR, false); BOOST_CHECK (prop); BOOST_CHECK (prop->mType == MTP_TYPE_STR); BOOST_CHECK (prop->mCode == MTP_PROPERTY_NAME); BOOST_CHECK (prop->mWriteable == false); BOOST_CHECK (prop->mDefaultValue.u.u64 == 0); BOOST_CHECK (prop->mCurrentValue.u.u64 == 0); } BOOST_AUTO_TEST_CASE(PropertyConstructorUInt32) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, true, 42); BOOST_CHECK (prop); BOOST_CHECK (prop->mType == MTP_TYPE_UINT32); BOOST_CHECK (prop->mCode == MTP_PROPERTY_STORAGE_ID); BOOST_CHECK (prop->mWriteable == true); BOOST_CHECK (prop->mDefaultValue.u.u32 == 42); BOOST_CHECK (prop->mCurrentValue.u.u64 == 0); } BOOST_AUTO_TEST_CASE(PropertySetFormRange) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, true, 42); prop->setFormRange(0, 90, 2); BOOST_CHECK(prop->mMinimumValue.u.u32 == 0); BOOST_CHECK(prop->mMaximumValue.u.u32 == 90); BOOST_CHECK(prop->mStepSize.u.u32 == 2); } BOOST_AUTO_TEST_CASE(PropertySetFormEnum) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, true, 42); const int values[4] = { 1, 2, 3, 4, }; prop->setFormEnum(values, 4); BOOST_CHECK(prop->mEnumValues[0].u.u32 == 1); BOOST_CHECK(prop->mEnumValues[1].u.u32 == 2); BOOST_CHECK(prop->mEnumValues[2].u.u32 == 3); BOOST_CHECK(prop->mEnumValues[3].u.u32 == 4); } BOOST_AUTO_TEST_CASE(PropertySetFormDateTime) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, true, 42); prop->setFormDateTime(); BOOST_CHECK(prop->mFormFlag == MtpProperty::kFormDateTime); } BOOST_AUTO_TEST_CASE(PropertyPrintToBuffer) { MtpProperty *prop = new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, true, 42); std::string expected ("42"); std::string result; prop->print(prop->mDefaultValue, result); BOOST_CHECK (result == expected); } mtp-0.0.3+14.04.20140409/tests/TestMtpUtils.cpp0000644000015301777760000000247412321133655021212 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include // #include #include "MtpUtils.h" using namespace android; BOOST_AUTO_TEST_CASE(UtilsParseDateTime) { time_t seconds; setenv("TZ", "UTC", 1); parseDateTime("20130909T114143", seconds); BOOST_CHECK_EQUAL(seconds, 1378726903l); } BOOST_AUTO_TEST_CASE(UtilsFormatDateTime) { time_t seconds = 1378726903; char buffer[25]; char *expected = "20130909T114143"; setenv("TZ", "UTC", 1); formatDateTime(seconds, buffer, 25); BOOST_CHECK_EQUAL(strcmp(expected, buffer), 0); } mtp-0.0.3+14.04.20140409/tests/TestMtpStorage.cpp0000644000015301777760000000471712321133655021520 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include #include "mtp.h" #include "MtpStorage.h" using namespace android; BOOST_AUTO_TEST_CASE(StorageConstructor) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, false, 64); BOOST_CHECK(s); } BOOST_AUTO_TEST_CASE(StorageGetTypeFixed) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, false, 64); BOOST_CHECK (s->getType() == MTP_STORAGE_FIXED_RAM); } BOOST_AUTO_TEST_CASE(StorageGetTypeRemovable) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, true, 64); BOOST_CHECK (s->getType() == MTP_STORAGE_REMOVABLE_RAM); } BOOST_AUTO_TEST_CASE(StorageGetFileSystemType) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, true, 64); BOOST_CHECK (s->getFileSystemType() == MTP_STORAGE_FILESYSTEM_HIERARCHICAL); } BOOST_AUTO_TEST_CASE(StorageGetAccessCapa) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, true, 64); BOOST_CHECK (s->getAccessCapability() == MTP_STORAGE_READ_WRITE); } BOOST_AUTO_TEST_CASE(StorageGetMaxCapacity) { MtpStorage *s = new MtpStorage (666, "/tmp", "Test storage", 0, true, 64); BOOST_CHECK (s->getMaxCapacity() > 0); } BOOST_AUTO_TEST_CASE(StorageGetMaxCapacityInvalidPath) { MtpStorage *s = new MtpStorage (666, "", "Test storage", 0, true, 64); BOOST_CHECK (s->getMaxCapacity() == -1); } BOOST_AUTO_TEST_CASE(StoageGetFreeSpace) { MtpStorage *s = new MtpStorage (666, "/", "Test storage", 0, true, 64); BOOST_CHECK (s->getFreeSpace() != -1); } BOOST_AUTO_TEST_CASE(StorageGetDescription) { MtpStorage *s = new MtpStorage (666, "/", "Test storage", 0, true, 64); BOOST_CHECK_EQUAL( strcmp( s->getDescription(), "Test storage" ), 0); } mtp-0.0.3+14.04.20140409/libusbhost/0000755000015301777760000000000012321134053017063 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/libusbhost/CMakeLists.txt0000644000015301777760000000020312321133655021625 0ustar pbusernogroup00000000000000project(usbhost) cmake_minimum_required(VERSION 2.8) include_directories(include/) add_library( usbhost src/usbhost.c ) mtp-0.0.3+14.04.20140409/libusbhost/src/0000755000015301777760000000000012321134053017652 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/libusbhost/src/usbhost.c0000644000015301777760000004404412321133675021524 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #define DEBUG 1 #if DEBUG #ifdef USE_LIBLOG #define LOG_TAG "usbhost" #define D printf #endif #else #define D(...) #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usbhost/usbhost.h" #define DEV_DIR "/dev" #define USB_FS_DIR "/dev/bus/usb" #define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d" #define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d" // From drivers/usb/core/devio.c // I don't know why this isn't in a kernel header #define MAX_USBFS_BUFFER_SIZE 16384 struct usb_host_context { int fd; }; struct usb_device { char dev_name[64]; unsigned char desc[4096]; int desc_length; int fd; int writeable; }; static inline int badname(const char *name) { while(*name) { if(!isdigit(*name++)) return 1; } return 0; } static int find_existing_devices_bus(char *busname, usb_device_added_cb added_cb, void *client_data) { char devname[32]; DIR *devdir; struct dirent *de; int done = 0; devdir = opendir(busname); if(devdir == 0) return 0; while ((de = readdir(devdir)) && !done) { if(badname(de->d_name)) continue; snprintf(devname, sizeof(devname), "%s/%s", busname, de->d_name); done = added_cb(devname, client_data); } // end of devdir while closedir(devdir); return done; } /* returns true if one of the callbacks indicates we are done */ static int find_existing_devices(usb_device_added_cb added_cb, void *client_data) { char busname[32]; DIR *busdir; struct dirent *de; int done = 0; busdir = opendir(USB_FS_DIR); if(busdir == 0) return 0; while ((de = readdir(busdir)) != 0 && !done) { if(badname(de->d_name)) continue; snprintf(busname, sizeof(busname), "%s/%s", USB_FS_DIR, de->d_name); done = find_existing_devices_bus(busname, added_cb, client_data); } closedir(busdir); return done; } static void watch_existing_subdirs(struct usb_host_context *context, int *wds, int wd_count) { char path[100]; int i, ret; wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE); if (wds[0] < 0) return; /* watch existing subdirectories of USB_FS_DIR */ for (i = 1; i < wd_count; i++) { snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i); ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); if (ret >= 0) wds[i] = ret; } } struct usb_host_context *usb_host_init() { struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context)); if (!context) { fprintf(stderr, "out of memory in usb_host_context\n"); return NULL; } context->fd = inotify_init(); if (context->fd < 0) { fprintf(stderr, "inotify_init failed\n"); free(context); return NULL; } return context; } void usb_host_cleanup(struct usb_host_context *context) { close(context->fd); free(context); } void usb_host_run(struct usb_host_context *context, usb_device_added_cb added_cb, usb_device_removed_cb removed_cb, usb_discovery_done_cb discovery_done_cb, void *client_data) { struct inotify_event* event; char event_buf[512]; char path[100]; int i, ret, done = 0; int wd, wdd, wds[10]; int wd_count = sizeof(wds) / sizeof(wds[0]); D("Created device discovery thread\n"); /* watch for files added and deleted within USB_FS_DIR */ for (i = 0; i < wd_count; i++) wds[i] = -1; /* watch the root for new subdirectories */ wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE); if (wdd < 0) { fprintf(stderr, "inotify_add_watch failed\n"); if (discovery_done_cb) discovery_done_cb(client_data); return; } watch_existing_subdirs(context, wds, wd_count); /* check for existing devices first, after we have inotify set up */ done = find_existing_devices(added_cb, client_data); if (discovery_done_cb) done |= discovery_done_cb(client_data); while (!done) { ret = read(context->fd, event_buf, sizeof(event_buf)); if (ret >= (int)sizeof(struct inotify_event)) { event = (struct inotify_event *)event_buf; wd = event->wd; if (wd == wdd) { if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) { watch_existing_subdirs(context, wds, wd_count); done = find_existing_devices(added_cb, client_data); } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) { for (i = 0; i < wd_count; i++) { if (wds[i] >= 0) { inotify_rm_watch(context->fd, wds[i]); wds[i] = -1; } } } } else if (wd == wds[0]) { i = atoi(event->name); snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name); D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ? "new" : "gone", path, i); if (i > 0 && i < wd_count) { if (event->mask & IN_CREATE) { ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); if (ret >= 0) wds[i] = ret; done = find_existing_devices_bus(path, added_cb, client_data); } else if (event->mask & IN_DELETE) { inotify_rm_watch(context->fd, wds[i]); wds[i] = -1; } } } else { for (i = 1; i < wd_count && !done; i++) { if (wd == wds[i]) { snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name); if (event->mask == IN_CREATE) { D("new device %s\n", path); done = added_cb(path, client_data); } else if (event->mask == IN_DELETE) { D("gone device %s\n", path); done = removed_cb(path, client_data); } } } } } } } struct usb_device *usb_device_open(const char *dev_name) { int fd, did_retry = 0, writeable = 1; D("usb_device_open %s\n", dev_name); retry: fd = open(dev_name, O_RDWR); if (fd < 0) { /* if we fail, see if have read-only access */ fd = open(dev_name, O_RDONLY); D("usb_device_open open returned %d errno %d\n", fd, errno); if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) { /* work around race condition between inotify and permissions management */ sleep(1); did_retry = 1; goto retry; } if (fd < 0) return NULL; writeable = 0; D("[ usb open read-only %s fd = %d]\n", dev_name, fd); } struct usb_device* result = usb_device_new(dev_name, fd); if (result) result->writeable = writeable; return result; } void usb_device_close(struct usb_device *device) { close(device->fd); free(device); } struct usb_device *usb_device_new(const char *dev_name, int fd) { struct usb_device *device = calloc(1, sizeof(struct usb_device)); int length; D("usb_device_new %s fd: %d\n", dev_name, fd); if (lseek(fd, 0, SEEK_SET) != 0) goto failed; length = read(fd, device->desc, sizeof(device->desc)); D("usb_device_new read returned %d errno %d\n", length, errno); if (length < 0) goto failed; strncpy(device->dev_name, dev_name, sizeof(device->dev_name) - 1); device->fd = fd; device->desc_length = length; // assume we are writeable, since usb_device_get_fd will only return writeable fds device->writeable = 1; return device; failed: close(fd); free(device); return NULL; } static int usb_device_reopen_writeable(struct usb_device *device) { if (device->writeable) return 1; int fd = open(device->dev_name, O_RDWR); if (fd >= 0) { close(device->fd); device->fd = fd; device->writeable = 1; return 1; } D("usb_device_reopen_writeable failed errno %d\n", errno); return 0; } int usb_device_get_fd(struct usb_device *device) { if (!usb_device_reopen_writeable(device)) return -1; return device->fd; } const char* usb_device_get_name(struct usb_device *device) { return device->dev_name; } int usb_device_get_unique_id(struct usb_device *device) { int bus = 0, dev = 0; sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev); return bus * 1000 + dev; } int usb_device_get_unique_id_from_name(const char* name) { int bus = 0, dev = 0; sscanf(name, USB_FS_ID_SCANNER, &bus, &dev); return bus * 1000 + dev; } char* usb_device_get_name_from_unique_id(int id) { int bus = id / 1000; int dev = id % 1000; char* result = (char *)calloc(1, strlen(USB_FS_ID_FORMAT)); snprintf(result, strlen(USB_FS_ID_FORMAT) - 1, USB_FS_ID_FORMAT, bus, dev); return result; } uint16_t usb_device_get_vendor_id(struct usb_device *device) { struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc; return __le16_to_cpu(desc->idVendor); } uint16_t usb_device_get_product_id(struct usb_device *device) { struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc; return __le16_to_cpu(desc->idProduct); } const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device) { return (struct usb_device_descriptor*)device->desc; } char* usb_device_get_string(struct usb_device *device, int id) { char string[256]; __u16 buffer[128]; __u16 languages[128]; int i, result; int languageCount = 0; string[0] = 0; memset(languages, 0, sizeof(languages)); // read list of supported languages result = usb_device_control_transfer(device, USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0); if (result > 0) languageCount = (result - 2) / 2; for (i = 1; i <= languageCount; i++) { memset(buffer, 0, sizeof(buffer)); result = usb_device_control_transfer(device, USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0); if (result > 0) { int i; // skip first word, and copy the rest to the string, changing shorts to bytes. result /= 2; for (i = 1; i < result; i++) string[i - 1] = buffer[i]; string[i - 1] = 0; return strdup(string); } } return NULL; } char* usb_device_get_manufacturer_name(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; if (desc->iManufacturer) return usb_device_get_string(device, desc->iManufacturer); else return NULL; } char* usb_device_get_product_name(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; if (desc->iProduct) return usb_device_get_string(device, desc->iProduct); else return NULL; } char* usb_device_get_serial(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; if (desc->iSerialNumber) return usb_device_get_string(device, desc->iSerialNumber); else return NULL; } int usb_device_is_writeable(struct usb_device *device) { return device->writeable; } void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter) { iter->config = device->desc; iter->config_end = device->desc + device->desc_length; iter->curr_desc = device->desc; } struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter) { struct usb_descriptor_header* next; if (iter->curr_desc >= iter->config_end) return NULL; next = (struct usb_descriptor_header*)iter->curr_desc; iter->curr_desc += next->bLength; return next; } int usb_device_claim_interface(struct usb_device *device, unsigned int interface) { return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface); } int usb_device_release_interface(struct usb_device *device, unsigned int interface) { return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface); } int usb_device_connect_kernel_driver(struct usb_device *device, unsigned int interface, int connect) { struct usbdevfs_ioctl ctl; ctl.ifno = interface; ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT); ctl.data = NULL; return ioctl(device->fd, USBDEVFS_IOCTL, &ctl); } int usb_device_control_transfer(struct usb_device *device, int requestType, int request, int value, int index, void* buffer, int length, unsigned int timeout) { struct usbdevfs_ctrltransfer ctrl; // this usually requires read/write permission if (!usb_device_reopen_writeable(device)) return -1; memset(&ctrl, 0, sizeof(ctrl)); ctrl.bRequestType = requestType; ctrl.bRequest = request; ctrl.wValue = value; ctrl.wIndex = index; ctrl.wLength = length; ctrl.data = buffer; ctrl.timeout = timeout; return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl); } int usb_device_bulk_transfer(struct usb_device *device, int endpoint, void* buffer, int length, unsigned int timeout) { struct usbdevfs_bulktransfer ctrl; // need to limit request size to avoid EINVAL if (length > MAX_USBFS_BUFFER_SIZE) length = MAX_USBFS_BUFFER_SIZE; memset(&ctrl, 0, sizeof(ctrl)); ctrl.ep = endpoint; ctrl.len = length; ctrl.data = buffer; ctrl.timeout = timeout; return ioctl(device->fd, USBDEVFS_BULK, &ctrl); } struct usb_request *usb_request_new(struct usb_device *dev, const struct usb_endpoint_descriptor *ep_desc) { struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb)); if (!urb) return NULL; if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) urb->type = USBDEVFS_URB_TYPE_BULK; else if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) urb->type = USBDEVFS_URB_TYPE_INTERRUPT; else { D("Unsupported endpoint type %d", ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); free(urb); return NULL; } urb->endpoint = ep_desc->bEndpointAddress; struct usb_request *req = calloc(1, sizeof(struct usb_request)); if (!req) { free(urb); return NULL; } req->dev = dev; req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize); req->private_data = urb; req->endpoint = urb->endpoint; urb->usercontext = req; return req; } void usb_request_free(struct usb_request *req) { free(req->private_data); free(req); } int usb_request_queue(struct usb_request *req) { struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data; int res; urb->status = -1; urb->buffer = req->buffer; // need to limit request size to avoid EINVAL if (req->buffer_length > MAX_USBFS_BUFFER_SIZE) urb->buffer_length = MAX_USBFS_BUFFER_SIZE; else urb->buffer_length = req->buffer_length; do { res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb); } while((res < 0) && (errno == EINTR)); return res; } struct usb_request *usb_request_wait(struct usb_device *dev) { struct usbdevfs_urb *urb = NULL; struct usb_request *req = NULL; int res; while (1) { int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb); D("USBDEVFS_REAPURB returned %d\n", res); if (res < 0) { if(errno == EINTR) { continue; } D("[ reap urb - error ]\n"); return NULL; } else { D("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length); req = (struct usb_request*)urb->usercontext; req->actual_length = urb->actual_length; } break; } return req; } int usb_request_cancel(struct usb_request *req) { struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data); return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb); } mtp-0.0.3+14.04.20140409/libusbhost/include/0000755000015301777760000000000012321134053020506 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/libusbhost/include/usbhost/0000755000015301777760000000000012321134053022175 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/libusbhost/include/usbhost/usbhost.h0000644000015301777760000001717312321133655024055 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __USB_HOST_H #define __USB_HOST_H #ifdef __cplusplus extern "C" { #endif #include #include #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) #include #else #include #endif struct usb_host_context; struct usb_endpoint_descriptor; struct usb_descriptor_iter { unsigned char* config; unsigned char* config_end; unsigned char* curr_desc; }; struct usb_request { struct usb_device *dev; void* buffer; int buffer_length; int actual_length; int max_packet_size; void *private_data; /* struct usbdevfs_urb* */ int endpoint; void *client_data; /* free for use by client */ }; /* Callback for notification when new USB devices are attached. * Return true to exit from usb_host_run. */ typedef int (* usb_device_added_cb)(const char *dev_name, void *client_data); /* Callback for notification when USB devices are removed. * Return true to exit from usb_host_run. */ typedef int (* usb_device_removed_cb)(const char *dev_name, void *client_data); /* Callback indicating that initial device discovery is done. * Return true to exit from usb_host_run. */ typedef int (* usb_discovery_done_cb)(void *client_data); /* Call this to initialize the USB host library. */ struct usb_host_context *usb_host_init(void); /* Call this to cleanup the USB host library. */ void usb_host_cleanup(struct usb_host_context *context); /* Call this to monitor the USB bus for new and removed devices. * This is intended to be called from a dedicated thread, * as it will not return until one of the callbacks returns true. * added_cb will be called immediately for each existing USB device, * and subsequently each time a new device is added. * removed_cb is called when USB devices are removed from the bus. * discovery_done_cb is called after the initial discovery of already * connected devices is complete. */ void usb_host_run(struct usb_host_context *context, usb_device_added_cb added_cb, usb_device_removed_cb removed_cb, usb_discovery_done_cb discovery_done_cb, void *client_data); /* Creates a usb_device object for a USB device */ struct usb_device *usb_device_open(const char *dev_name); /* Releases all resources associated with the USB device */ void usb_device_close(struct usb_device *device); /* Creates a usb_device object for already open USB device */ struct usb_device *usb_device_new(const char *dev_name, int fd); /* Returns the file descriptor for the usb_device */ int usb_device_get_fd(struct usb_device *device); /* Returns the name for the USB device, which is the same as * the dev_name passed to usb_device_open() */ const char* usb_device_get_name(struct usb_device *device); /* Returns a unique ID for the device. *Currently this is generated from the dev_name path. */ int usb_device_get_unique_id(struct usb_device *device); /* Returns a unique ID for the device name. * Currently this is generated from the device path. */ int usb_device_get_unique_id_from_name(const char* name); /* Returns the device name for the unique ID. * Call free() to deallocate the returned string */ char* usb_device_get_name_from_unique_id(int id); /* Returns the USB vendor ID from the device descriptor for the USB device */ uint16_t usb_device_get_vendor_id(struct usb_device *device); /* Returns the USB product ID from the device descriptor for the USB device */ uint16_t usb_device_get_product_id(struct usb_device *device); const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device); /* Returns a USB descriptor string for the given string ID. * Used to implement usb_device_get_manufacturer_name, * usb_device_get_product_name and usb_device_get_serial. * Call free() to free the result when you are done with it. */ char* usb_device_get_string(struct usb_device *device, int id); /* Returns the manufacturer name for the USB device. * Call free() to free the result when you are done with it. */ char* usb_device_get_manufacturer_name(struct usb_device *device); /* Returns the product name for the USB device. * Call free() to free the result when you are done with it. */ char* usb_device_get_product_name(struct usb_device *device); /* Returns the USB serial number for the USB device. * Call free() to free the result when you are done with it. */ char* usb_device_get_serial(struct usb_device *device); /* Returns true if we have write access to the USB device, * and false if we only have access to the USB device configuration. */ int usb_device_is_writeable(struct usb_device *device); /* Initializes a usb_descriptor_iter, which can be used to iterate through all * the USB descriptors for a USB device. */ void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter); /* Returns the next USB descriptor for a device, or NULL if we have reached the * end of the list. */ struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter); /* Claims the specified interface of a USB device */ int usb_device_claim_interface(struct usb_device *device, unsigned int interface); /* Releases the specified interface of a USB device */ int usb_device_release_interface(struct usb_device *device, unsigned int interface); /* Requests the kernel to connect or disconnect its driver for the specified interface. * This can be used to ask the kernel to disconnect its driver for a device * so usb_device_claim_interface can claim it instead. */ int usb_device_connect_kernel_driver(struct usb_device *device, unsigned int interface, int connect); /* Sends a control message to the specified device on endpoint zero */ int usb_device_control_transfer(struct usb_device *device, int requestType, int request, int value, int index, void* buffer, int length, unsigned int timeout); /* Reads or writes on a bulk endpoint. * Returns number of bytes transferred, or negative value for error. */ int usb_device_bulk_transfer(struct usb_device *device, int endpoint, void* buffer, int length, unsigned int timeout); /* Creates a new usb_request. */ struct usb_request *usb_request_new(struct usb_device *dev, const struct usb_endpoint_descriptor *ep_desc); /* Releases all resources associated with the request */ void usb_request_free(struct usb_request *req); /* Submits a read or write request on the specified device */ int usb_request_queue(struct usb_request *req); /* Waits for the results of a previous usb_request_queue operation. * Returns a usb_request, or NULL for error. */ struct usb_request *usb_request_wait(struct usb_device *dev); /* Cancels a pending usb_request_queue() operation. */ int usb_request_cancel(struct usb_request *req); #ifdef __cplusplus } #endif #endif /* __USB_HOST_H */ mtp-0.0.3+14.04.20140409/server/0000755000015301777760000000000012321134053016213 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/server/CMakeLists.txt0000644000015301777760000000067412321133675020773 0ustar pbusernogroup00000000000000add_definitions(-DMTP_DEVICE -DMTP_HOST) add_executable( mtp-server server.cpp ) set_target_properties(mtp-server PROPERTIES COMPILE_FLAGS -fPIC) target_link_libraries( mtp-server mtpserver usbhost android-properties ${Boost_LIBRARIES} ${Boost_thread_LIBRARIES} ${Boost_system_LIBRARIES} ${Boost_filesystem_LIBRARIES} ${GLOG_LIBRARIES} ) install( TARGETS mtp-server RUNTIME DESTINATION bin ) mtp-0.0.3+14.04.20140409/server/server.cpp0000644000015301777760000000470512321133675020244 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "UbuntuMtpDatabase.h" #include #include #include #include #include #include #include #include #include #include #include namespace { struct FileSystemConfig { static const int file_perm = 0664; static const int directory_perm = 0755; }; android::MtpStorage* home_storage; } int main(int argc, char** argv) { struct passwd *userdata = getpwuid (getuid()); char product_name[PROP_VALUE_MAX]; int fd = open("/dev/mtp_usb", O_RDWR); google::InitGoogleLogging(argv[0]); LOG(INFO) << "MTP server starting..."; if (fd < 0) { LOG(FATAL) << "Error opening /dev/mtp_usb, aborting now..."; } std::shared_ptr server { new android::MtpServer( fd, new android::UbuntuMtpDatabase(userdata->pw_dir), false, userdata->pw_gid, FileSystemConfig::file_perm, FileSystemConfig::directory_perm) }; property_get ("ro.product.model", product_name, "Ubuntu Touch device"); home_storage = new android::MtpStorage( MTP_STORAGE_FIXED_RAM, userdata->pw_dir, product_name, 1024 * 1024 * 100, /* 100 MB reserved space, to avoid filling the disk */ false, 1024 * 1024 * 1024 * 2 /* 2GB arbitrary max file size */); server->addStorage(home_storage); server->run(); /* std::thread t{[&server](){ server->run(); }}; sigset_t signal_set; sigemptyset(&signal_set); sigaddset(&signal_set, SIGINT); int signal; sigwait(&signal_set, &signal); if (t.joinable()) t.join(); */ } mtp-0.0.3+14.04.20140409/server/UbuntuMtpDatabase.h0000644000015301777760000005601012321133675021767 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef STUB_MTP_DATABASE_H_ #define STUB_MTP_DATABASE_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace asio = boost::asio; using namespace boost::filesystem; namespace android { class UbuntuMtpDatabase : public android::MtpDatabase { private: struct DbEntry { MtpStorageID storage_id; MtpObjectFormat object_format; MtpObjectHandle parent; size_t object_size; std::string display_name; std::string path; int watch_fd; }; MtpServer* local_server; uint32_t counter; std::map db; std::map formats = boost::assign::map_list_of (".gif", MTP_FORMAT_GIF) (".png", MTP_FORMAT_PNG) (".jpeg", MTP_FORMAT_JFIF) (".tiff", MTP_FORMAT_TIFF) (".ogg", MTP_FORMAT_OGG) (".mp3", MTP_FORMAT_MP3) (".wav", MTP_FORMAT_WAV) (".wma", MTP_FORMAT_WMA) (".aac", MTP_FORMAT_AAC) (".flac", MTP_FORMAT_FLAC); boost::thread notifier_thread; boost::thread io_service_thread; asio::io_service io_svc; asio::posix::stream_descriptor stream_desc; asio::streambuf buf; int inotify_fd; MtpObjectFormat guess_object_format(std::string extension) { std::map::iterator it; it = formats.find(extension); if (it == formats.end()) { boost::to_upper(extension); it = formats.find(extension); if (it == formats.end()) { return MTP_FORMAT_UNDEFINED; } } return it->second; } int setup_dir_inotify(path p) { return inotify_add_watch(inotify_fd, p.string().c_str(), IN_MODIFY | IN_CREATE | IN_DELETE); } void add_file_entry(path p, MtpObjectHandle parent) { MtpObjectHandle handle = counter; DbEntry entry; counter++; if (is_directory(p)) { entry.storage_id = MTP_STORAGE_FIXED_RAM; entry.parent = parent; entry.display_name = std::string(p.filename().string()); entry.path = p.string(); entry.object_format = MTP_FORMAT_ASSOCIATION; entry.object_size = 0; entry.watch_fd = setup_dir_inotify(p); db.insert( std::pair(handle, entry) ); if (local_server) local_server->sendObjectAdded(handle); parse_directory (p, handle); } else { try { entry.storage_id = MTP_STORAGE_FIXED_RAM; entry.parent = parent; entry.display_name = std::string(p.filename().string()); entry.path = p.string(); entry.object_format = guess_object_format(p.extension().string()); entry.object_size = file_size(p); VLOG(1) << "Adding \"" << p.string() << "\""; db.insert( std::pair(handle, entry) ); if (local_server) local_server->sendObjectAdded(handle); } catch (const filesystem_error& ex) { PLOG(WARNING) << "There was an error reading file properties"; } } } void parse_directory(path p, MtpObjectHandle parent) { DbEntry entry; std::vector v; copy(directory_iterator(p), directory_iterator(), std::back_inserter(v)); for (std::vector::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it) { add_file_entry(*it, parent); } } void readFiles(const std::string& sourcedir) { path p (sourcedir); DbEntry entry; MtpObjectHandle handle = counter++; try { if (exists(p)) { if (is_directory(p)) { entry.storage_id = MTP_STORAGE_FIXED_RAM; entry.parent = MTP_PARENT_ROOT; entry.display_name = std::string(p.filename().string()); entry.path = p.string(); entry.object_format = MTP_FORMAT_ASSOCIATION; entry.object_size = 0; entry.watch_fd = setup_dir_inotify(p); db.insert( std::pair(handle, entry) ); parse_directory (p, handle); } } else LOG(WARNING) << p << " does not exist\n"; } catch (const filesystem_error& ex) { LOG(ERROR) << ex.what(); } } void read_more_notify() { stream_desc.async_read_some(buf.prepare(buf.max_size()), boost::bind(&UbuntuMtpDatabase::inotify_handler, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); } void inotify_handler(const boost::system::error_code&, std::size_t transferred) { size_t processed = 0; while(transferred - processed >= sizeof(inotify_event)) { const char* cdata = processed + asio::buffer_cast(buf.data()); const inotify_event* ievent = reinterpret_cast(cdata); MtpObjectHandle parent; processed += sizeof(inotify_event) + ievent->len; BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).watch_fd == ievent->wd) { parent = i; break; } } path p(db.at(parent).path + "/" + ievent->name); if(ievent->len > 0 && ievent->mask & IN_MODIFY) { VLOG(2) << __PRETTY_FUNCTION__ << ": file modified: " << p.string(); BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).path == p.string()) { try { VLOG(2) << "new size: " << file_size(p); db.at(i).object_size = file_size(p); } catch (const filesystem_error& ex) { PLOG(WARNING) << "There was an error reading file properties"; } } } } else if(ievent->len > 0 && ievent->mask & IN_CREATE) { VLOG(2) << __PRETTY_FUNCTION__ << ": file created: " << p.string(); /* try to deal with it as if it was a file. */ add_file_entry(p, parent); } else if(ievent->len > 0 && ievent->mask & IN_DELETE) { VLOG(2) << __PRETTY_FUNCTION__ << ": file deleted: " << p.string(); BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).path == p.string()) { VLOG(2) << "deleting file at handle " << i; deleteFile(i); if (local_server) local_server->sendObjectRemoved(i); break; } } } } read_more_notify(); } public: UbuntuMtpDatabase(const char *dir): counter(1), stream_desc(io_svc), buf(1024) { std::string basedir (dir); local_server = nullptr; inotify_fd = inotify_init(); if (inotify_fd <= 0) PLOG(FATAL) << "Unable to initialize inotify"; stream_desc.assign(inotify_fd); db = std::map(); notifier_thread = boost::thread(&UbuntuMtpDatabase::read_more_notify, this); readFiles(basedir + "/Documents"); readFiles(basedir + "/Music"); readFiles(basedir + "/Videos"); readFiles(basedir + "/Pictures"); readFiles(basedir + "/Downloads"); LOG(INFO) << "Added " << counter << " entries to the database."; io_service_thread = boost::thread(boost::bind(&asio::io_service::run, &io_svc)); } virtual ~UbuntuMtpDatabase() { io_svc.stop(); notifier_thread.detach(); io_service_thread.join(); close(inotify_fd); } // called from SendObjectInfo to reserve a database entry for the incoming file virtual MtpObjectHandle beginSendObject( const MtpString& path, MtpObjectFormat format, MtpObjectHandle parent, MtpStorageID storage, uint64_t size, time_t modified) { DbEntry entry; MtpObjectHandle handle = counter; if (parent == 0) return kInvalidObjectHandle; VLOG(1) << __PRETTY_FUNCTION__ << ": " << path << " - " << parent; entry.storage_id = storage; entry.parent = parent; entry.display_name = std::string(basename(path.c_str())); entry.path = path; entry.object_format = format; entry.object_size = size; db.insert( std::pair(handle, entry) ); counter++; return handle; } // called to report success or failure of the SendObject file transfer // success should signal a notification of the new object's creation, // failure should remove the database entry created in beginSendObject virtual void endSendObject( const MtpString& path, MtpObjectHandle handle, MtpObjectFormat format, bool succeeded) { VLOG(1) << __PRETTY_FUNCTION__ << ": " << path; if (!succeeded) { db.erase(handle); } else { boost::filesystem::path p (path); if (format != MTP_FORMAT_ASSOCIATION) { /* Resync file size, just in case this is actually an Edit. */ db.at(handle).object_size = file_size(p); } } } virtual MtpObjectHandleList* getObjectList( MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { VLOG(1) << __PRETTY_FUNCTION__ << ": " << storageID << ", " << format << ", " << parent; MtpObjectHandleList* list = nullptr; try { std::vector keys; BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).parent == parent) keys.push_back(i); } list = new MtpObjectHandleList(keys); } catch(...) { list = new MtpObjectHandleList(); } return list; } virtual int getNumObjects( MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { VLOG(1) << __PRETTY_FUNCTION__ << ": " << storageID << ", " << format << ", " << parent; try { return db.size(); } catch(...) { } return 0; } // callee should delete[] the results from these // results can be NULL virtual MtpObjectFormatList* getSupportedPlaybackFormats() { VLOG(1) << __PRETTY_FUNCTION__; static const MtpObjectFormatList list = { /* Generic files */ MTP_FORMAT_UNDEFINED, /* Supported audio formats */ MTP_FORMAT_OGG, MTP_FORMAT_MP3, MTP_FORMAT_WAV, MTP_FORMAT_WMA, MTP_FORMAT_AAC, MTP_FORMAT_FLAC, /* Supported video formats */ // none listed yet, video apparently broken. /* Audio album, and album art */ MTP_FORMAT_ABSTRACT_AUDIO_ALBUM, /* Playlists for audio and video */ MTP_FORMAT_ABSTRACT_AV_PLAYLIST, }; return new MtpObjectFormatList{list}; } virtual MtpObjectFormatList* getSupportedCaptureFormats() { VLOG(1) << __PRETTY_FUNCTION__; static const MtpObjectFormatList list = {MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG}; return new MtpObjectFormatList{list}; } virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format) { VLOG(1) << __PRETTY_FUNCTION__; /* if (format != MTP_FORMAT_PNG) return nullptr; */ static const MtpObjectPropertyList list = { MTP_PROPERTY_STORAGE_ID, MTP_PROPERTY_PARENT_OBJECT, MTP_PROPERTY_OBJECT_FORMAT, MTP_PROPERTY_OBJECT_SIZE, MTP_PROPERTY_WIDTH, MTP_PROPERTY_HEIGHT, MTP_PROPERTY_IMAGE_BIT_DEPTH, MTP_PROPERTY_OBJECT_FILE_NAME, MTP_PROPERTY_DISPLAY_NAME }; return new MtpObjectPropertyList{list}; } virtual MtpDevicePropertyList* getSupportedDeviceProperties() { VLOG(1) << __PRETTY_FUNCTION__; static const MtpDevicePropertyList list = { MTP_DEVICE_PROPERTY_UNDEFINED }; return new MtpDevicePropertyList{list}; } virtual MtpResponseCode getObjectPropertyValue( MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { VLOG(1) << __PRETTY_FUNCTION__ << " handle: " << handle << " property: " << MtpDebug::getObjectPropCodeName(property); switch(property) { case MTP_PROPERTY_STORAGE_ID: packet.putUInt32(db.at(handle).storage_id); break; case MTP_PROPERTY_PARENT_OBJECT: packet.putUInt32(db.at(handle).parent); break; case MTP_PROPERTY_OBJECT_FORMAT: packet.putUInt32(db.at(handle).object_format); break; case MTP_PROPERTY_OBJECT_SIZE: packet.putUInt32(db.at(handle).object_size); break; case MTP_PROPERTY_DISPLAY_NAME: packet.putString(db.at(handle).display_name.c_str()); break; case MTP_PROPERTY_OBJECT_FILE_NAME: packet.putString(db.at(handle).display_name.c_str()); break; default: return MTP_RESPONSE_GENERAL_ERROR; break; } return MTP_RESPONSE_OK; } virtual MtpResponseCode setObjectPropertyValue( MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { DbEntry entry; MtpStringBuffer buffer; std::string oldname; std::string newname; path oldpath; path newpath; VLOG(1) << __PRETTY_FUNCTION__ << " handle: " << handle << " property: " << MtpDebug::getObjectPropCodeName(property); switch(property) { case MTP_PROPERTY_OBJECT_FILE_NAME: try { entry = db.at(handle); packet.getString(buffer); newname = strdup(buffer); oldpath /= entry.path; newpath /= oldpath.branch_path() / "/" / newname; boost::filesystem::rename(oldpath, newpath); db.at(handle).display_name = newname; db.at(handle).path = newpath.string(); } catch (filesystem_error& fe) { LOG(ERROR) << fe.what(); return MTP_RESPONSE_DEVICE_BUSY; } catch (std::exception& e) { LOG(ERROR) << e.what(); return MTP_RESPONSE_GENERAL_ERROR; } catch (...) { LOG(ERROR) << "An unexpected error has occurred"; return MTP_RESPONSE_GENERAL_ERROR; } break; default: return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } return MTP_RESPONSE_OK; } virtual MtpResponseCode getDevicePropertyValue( MtpDeviceProperty property, MtpDataPacket& packet) { VLOG(1) << __PRETTY_FUNCTION__; return MTP_RESPONSE_GENERAL_ERROR; } virtual MtpResponseCode setDevicePropertyValue( MtpDeviceProperty property, MtpDataPacket& packet) { VLOG(1) << __PRETTY_FUNCTION__; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode resetDeviceProperty( MtpDeviceProperty property) { VLOG(1) << __PRETTY_FUNCTION__; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode getObjectPropertyList( MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { VLOG(2) << __PRETTY_FUNCTION__; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpResponseCode getObjectInfo( MtpObjectHandle handle, MtpObjectInfo& info) { VLOG(2) << __PRETTY_FUNCTION__; info.mHandle = handle; info.mStorageID = db.at(handle).storage_id; info.mFormat = db.at(handle).object_format; info.mProtectionStatus = 0x0; info.mCompressedSize = db.at(handle).object_size; info.mImagePixWidth = 0; info.mImagePixHeight = 0; info.mImagePixDepth = 0; info.mParent = db.at(handle).parent; info.mAssociationType = 0; info.mAssociationDesc = 0; info.mSequenceNumber = 0; info.mName = ::strdup(db.at(handle).display_name.c_str()); info.mDateCreated = 0; info.mDateModified = 0; info.mKeywords = ::strdup("ubuntu,touch"); if (VLOG_IS_ON(2)) info.print(); return MTP_RESPONSE_OK; } virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) { void* result; outThumbSize = 0; memset(result, 0, outThumbSize); return result; } virtual MtpResponseCode getObjectFilePath( MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) { DbEntry entry = db.at(handle); VLOG(1) << __PRETTY_FUNCTION__ << " handle: " << handle; outFilePath = std::string(entry.path); outFileLength = entry.object_size; outFormat = entry.object_format; return MTP_RESPONSE_OK; } virtual MtpResponseCode deleteFile(MtpObjectHandle handle) { size_t orig_size = db.size(); size_t new_size; VLOG(2) << __PRETTY_FUNCTION__ << " handle: " << handle; if (db.at(handle).object_format == MTP_FORMAT_ASSOCIATION) inotify_rm_watch(inotify_fd, db.at(handle).watch_fd); new_size = db.erase(handle); if (orig_size > new_size) { /* Recursively remove children object from the DB as well. * we can safely ignore failures here, since the objects * would not be reachable anyway. */ BOOST_FOREACH(MtpObjectHandle i, db | boost::adaptors::map_keys) { if (db.at(i).parent == handle) db.erase(i); } return MTP_RESPONSE_OK; } else return MTP_RESPONSE_GENERAL_ERROR; } virtual MtpResponseCode moveFile(MtpObjectHandle handle, MtpObjectHandle new_parent) { VLOG(1) << __PRETTY_FUNCTION__ << " handle: " << handle << " new parent: " << new_parent; // change parent db.at(handle).parent = new_parent; return MTP_RESPONSE_OK; } /* virtual MtpResponseCode copyFile(MtpObjectHandle handle, MtpObjectHandle new_parent) { VLOG(2) << __PRETTY_FUNCTION__; // duplicate DbEntry // change parent return MTP_RESPONSE_OK } */ virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle) { VLOG(1) << __PRETTY_FUNCTION__; return nullptr; } virtual MtpResponseCode setObjectReferences( MtpObjectHandle handle, MtpObjectHandleList* references) { VLOG(1) << __PRETTY_FUNCTION__; return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; } virtual MtpProperty* getObjectPropertyDesc( MtpObjectProperty property, MtpObjectFormat format) { VLOG(1) << __PRETTY_FUNCTION__ << MtpDebug::getObjectPropCodeName(property); MtpProperty* result = nullptr; switch(property) { case MTP_PROPERTY_STORAGE_ID: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_OBJECT_FORMAT: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_OBJECT_SIZE: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_WIDTH: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_HEIGHT: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_IMAGE_BIT_DEPTH: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_DISPLAY_NAME: result = new MtpProperty(property, MTP_TYPE_STR, true); break; case MTP_PROPERTY_OBJECT_FILE_NAME: result = new MtpProperty(property, MTP_TYPE_STR, true); break; default: break; } return result; } virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) { VLOG(1) << __PRETTY_FUNCTION__ << MtpDebug::getDevicePropCodeName(property); return new MtpProperty(MTP_DEVICE_PROPERTY_UNDEFINED, MTP_TYPE_UNDEFINED); } virtual void sessionStarted(MtpServer* server) { VLOG(1) << __PRETTY_FUNCTION__; local_server = server; } virtual void sessionEnded() { VLOG(1) << __PRETTY_FUNCTION__; VLOG(1) << "objects in db at session end: " << db.size(); local_server = nullptr; } }; } #endif // STUB_MTP_DATABASE_H_ mtp-0.0.3+14.04.20140409/MODULE_LICENSE_APACHE20000644000015301777760000000000012321133655020037 0ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/CMakeLists.txt0000644000015301777760000000362712321133675017466 0ustar pbusernogroup00000000000000project(mtpserver) cmake_minimum_required(VERSION 2.8) include(FindPkgConfig) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") add_definitions(-DMTP_DEVICE -DMTP_HOST) set(MTP_VERSION_MAJOR 1) set(MTP_VERSION_MINOR 0) set(MTP_VERSION_PATCH 0) find_package(Boost REQUIRED COMPONENTS thread system filesystem unit_test_framework) pkg_check_modules(GLOG libglog) set( MTP_HEADERS include/MtpDatabase.h include/MtpDataPacket.h include/MtpDebug.h include/MtpDevice.h include/MtpDeviceInfo.h include/MtpEventPacket.h include/mtp.h include/MtpObjectInfo.h include/MtpPacket.h include/MtpProperty.h include/MtpRequestPacket.h include/MtpResponsePacket.h include/MtpServer.h include/MtpStorage.h include/MtpStorageInfo.h include/MtpStringBuffer.h include/MtpTypes.h include/MtpUtils.h ) set( MTP_SRCS src/MtpDataPacket.cpp src/MtpDebug.cpp src/MtpDevice.cpp src/MtpDeviceInfo.cpp src/MtpEventPacket.cpp src/MtpObjectInfo.cpp src/MtpPacket.cpp src/MtpProperty.cpp src/MtpRequestPacket.cpp src/MtpResponsePacket.cpp src/MtpServer.cpp src/MtpStorage.cpp src/MtpStorageInfo.cpp src/MtpStringBuffer.cpp src/MtpUtils.cpp) include_directories( include/ libusbhost/include ${Boost_INCLUDE_DIRS} ) add_library( mtpserver SHARED ${MTP_SRCS} ) target_link_libraries( mtpserver android-properties ${GLOG_LIBRARIES} ) set_target_properties( mtpserver PROPERTIES VERSION ${MTP_VERSION_MAJOR}.${MTP_VERSION_MINOR}.${MTP_VERSION_PATCH} SOVERSION ${MTP_VERSION_MAJOR} ) set_target_properties( mtpserver PROPERTIES PUBLIC_HEADER "${MTP_HEADERS}" ) install( TARGETS mtpserver LIBRARY DESTINATION lib RUNTIME DESTINATION lib PUBLIC_HEADER DESTINATION include/mtp ) enable_testing() add_subdirectory(libusbhost) add_subdirectory(server) add_subdirectory(tests) mtp-0.0.3+14.04.20140409/COPYING0000644000015301777760000010451312321133655015753 0ustar pbusernogroup00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . mtp-0.0.3+14.04.20140409/src/0000755000015301777760000000000012321134053015474 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/src/MtpUtils.cpp0000644000015301777760000000502512321133655017772 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpUtils" #include #include // #include #include "MtpUtils.h" namespace android { /* DateTime strings follow a compatible subset of the definition found in ISO 8601, and take the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this representation, YYYY shall be replaced by the year, MM replaced by the month (01-12), DD replaced by the day (01-31), T is a constant character 'T' delimiting time from date, hh is replaced by the hour (00-23), mm is replaced by the minute (00-59), and ss by the second (00-59). The ".s" is optional, and represents tenths of a second. */ bool parseDateTime(const char* dateTime, time_t& outSeconds) { int year, month, day, hour, minute, second; struct tm tm; if (sscanf(dateTime, "%04d%02d%02dT%02d%02d%02d", &year, &month, &day, &hour, &minute, &second) != 6) return false; const char* tail = dateTime + 15; // skip optional tenth of second if (tail[0] == '.' && tail[1]) tail += 2; //FIXME - support +/-hhmm bool useUTC = (tail[0] == 'Z'); // hack to compute timezone time_t dummy; tzset(); localtime_r(&dummy, &tm); tm.tm_sec = second; tm.tm_min = minute; tm.tm_hour = hour; tm.tm_mday = day; tm.tm_mon = month - 1; // mktime uses months in 0 - 11 range tm.tm_year = year - 1900; tm.tm_wday = 0; tm.tm_isdst = -1; outSeconds = mktime(&tm); /*if (useUTC) outSeconds = mktime(&tm); else outSeconds = mktime_tz(&tm, tm.tm_zone);*/ return true; } void formatDateTime(time_t seconds, char* buffer, int bufferLength) { struct tm tm; localtime_r(&seconds, &tm); snprintf(buffer, bufferLength, "%04d%02d%02dT%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpProperty.cpp0000644000015301777760000004162512321133675020526 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpProperty" #include "MtpDataPacket.h" #include "MtpDebug.h" #include "MtpProperty.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" #include #include #include #include namespace android { MtpProperty::MtpProperty() : mCode(0), mType(0), mWriteable(false), mDefaultArrayLength(0), mDefaultArrayValues(NULL), mCurrentArrayLength(0), mCurrentArrayValues(NULL), mGroupCode(0), mFormFlag(kFormNone), mEnumLength(0), mEnumValues(NULL) { memset(&mDefaultValue, 0, sizeof(mDefaultValue)); memset(&mCurrentValue, 0, sizeof(mCurrentValue)); memset(&mMinimumValue, 0, sizeof(mMinimumValue)); memset(&mMaximumValue, 0, sizeof(mMaximumValue)); } MtpProperty::MtpProperty(MtpPropertyCode propCode, MtpDataType type, bool writeable, int defaultValue) : mCode(propCode), mType(type), mWriteable(writeable), mDefaultArrayLength(0), mDefaultArrayValues(NULL), mCurrentArrayLength(0), mCurrentArrayValues(NULL), mGroupCode(0), mFormFlag(kFormNone), mEnumLength(0), mEnumValues(NULL) { memset(&mDefaultValue, 0, sizeof(mDefaultValue)); memset(&mCurrentValue, 0, sizeof(mCurrentValue)); memset(&mMinimumValue, 0, sizeof(mMinimumValue)); memset(&mMaximumValue, 0, sizeof(mMaximumValue)); if (defaultValue) { switch (type) { case MTP_TYPE_INT8: mDefaultValue.u.i8 = defaultValue; break; case MTP_TYPE_UINT8: mDefaultValue.u.u8 = defaultValue; break; case MTP_TYPE_INT16: mDefaultValue.u.i16 = defaultValue; break; case MTP_TYPE_UINT16: mDefaultValue.u.u16 = defaultValue; break; case MTP_TYPE_INT32: mDefaultValue.u.i32 = defaultValue; break; case MTP_TYPE_UINT32: mDefaultValue.u.u32 = defaultValue; break; case MTP_TYPE_INT64: mDefaultValue.u.i64 = defaultValue; break; case MTP_TYPE_UINT64: mDefaultValue.u.u64 = defaultValue; break; default: LOG(ERROR) << "unknown type " << std::hex << type << std::dec << " in MtpProperty::MtpProperty"; } } } MtpProperty::~MtpProperty() { if (mType == MTP_TYPE_STR) { // free all strings free(mDefaultValue.str); free(mCurrentValue.str); free(mMinimumValue.str); free(mMaximumValue.str); if (mDefaultArrayValues) { for (int i = 0; i < mDefaultArrayLength; i++) free(mDefaultArrayValues[i].str); } if (mCurrentArrayValues) { for (int i = 0; i < mCurrentArrayLength; i++) free(mCurrentArrayValues[i].str); } if (mEnumValues) { for (int i = 0; i < mEnumLength; i++) free(mEnumValues[i].str); } } delete[] mDefaultArrayValues; delete[] mCurrentArrayValues; delete[] mEnumValues; } void MtpProperty::read(MtpDataPacket& packet) { mCode = packet.getUInt16(); bool deviceProp = isDeviceProperty(); mType = packet.getUInt16(); mWriteable = (packet.getUInt8() == 1); switch (mType) { case MTP_TYPE_AINT8: case MTP_TYPE_AUINT8: case MTP_TYPE_AINT16: case MTP_TYPE_AUINT16: case MTP_TYPE_AINT32: case MTP_TYPE_AUINT32: case MTP_TYPE_AINT64: case MTP_TYPE_AUINT64: case MTP_TYPE_AINT128: case MTP_TYPE_AUINT128: mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength); if (deviceProp) mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength); break; default: readValue(packet, mDefaultValue); if (deviceProp) readValue(packet, mCurrentValue); } if (!deviceProp) mGroupCode = packet.getUInt32(); mFormFlag = packet.getUInt8(); if (mFormFlag == kFormRange) { readValue(packet, mMinimumValue); readValue(packet, mMaximumValue); readValue(packet, mStepSize); } else if (mFormFlag == kFormEnum) { mEnumLength = packet.getUInt16(); mEnumValues = new MtpPropertyValue[mEnumLength]; for (int i = 0; i < mEnumLength; i++) readValue(packet, mEnumValues[i]); } } void MtpProperty::write(MtpDataPacket& packet) { bool deviceProp = isDeviceProperty(); packet.putUInt16(mCode); packet.putUInt16(mType); packet.putUInt8(mWriteable ? 1 : 0); switch (mType) { case MTP_TYPE_AINT8: case MTP_TYPE_AUINT8: case MTP_TYPE_AINT16: case MTP_TYPE_AUINT16: case MTP_TYPE_AINT32: case MTP_TYPE_AUINT32: case MTP_TYPE_AINT64: case MTP_TYPE_AUINT64: case MTP_TYPE_AINT128: case MTP_TYPE_AUINT128: writeArrayValues(packet, mDefaultArrayValues, mDefaultArrayLength); if (deviceProp) writeArrayValues(packet, mCurrentArrayValues, mCurrentArrayLength); break; default: writeValue(packet, mDefaultValue); if (deviceProp) writeValue(packet, mCurrentValue); } packet.putUInt32(mGroupCode); if (!deviceProp) packet.putUInt8(mFormFlag); if (mFormFlag == kFormRange) { writeValue(packet, mMinimumValue); writeValue(packet, mMaximumValue); writeValue(packet, mStepSize); } else if (mFormFlag == kFormEnum) { packet.putUInt16(mEnumLength); for (int i = 0; i < mEnumLength; i++) writeValue(packet, mEnumValues[i]); } } void MtpProperty::setDefaultValue(const uint16_t* string) { free(mDefaultValue.str); if (string) { MtpStringBuffer buffer(string); mDefaultValue.str = strdup(buffer); } else mDefaultValue.str = NULL; } void MtpProperty::setCurrentValue(const uint16_t* string) { free(mCurrentValue.str); if (string) { MtpStringBuffer buffer(string); mCurrentValue.str = strdup(buffer); } else mCurrentValue.str = NULL; } void MtpProperty::setFormRange(int min, int max, int step) { mFormFlag = kFormRange; switch (mType) { case MTP_TYPE_INT8: mMinimumValue.u.i8 = min; mMaximumValue.u.i8 = max; mStepSize.u.i8 = step; break; case MTP_TYPE_UINT8: mMinimumValue.u.u8 = min; mMaximumValue.u.u8 = max; mStepSize.u.u8 = step; break; case MTP_TYPE_INT16: mMinimumValue.u.i16 = min; mMaximumValue.u.i16 = max; mStepSize.u.i16 = step; break; case MTP_TYPE_UINT16: mMinimumValue.u.u16 = min; mMaximumValue.u.u16 = max; mStepSize.u.u16 = step; break; case MTP_TYPE_INT32: mMinimumValue.u.i32 = min; mMaximumValue.u.i32 = max; mStepSize.u.i32 = step; break; case MTP_TYPE_UINT32: mMinimumValue.u.u32 = min; mMaximumValue.u.u32 = max; mStepSize.u.u32 = step; break; case MTP_TYPE_INT64: mMinimumValue.u.i64 = min; mMaximumValue.u.i64 = max; mStepSize.u.i64 = step; break; case MTP_TYPE_UINT64: mMinimumValue.u.u64 = min; mMaximumValue.u.u64 = max; mStepSize.u.u64 = step; break; default: LOG(ERROR) << "unsupported type for MtpProperty::setRange"; break; } } void MtpProperty::setFormEnum(const int* values, int count) { mFormFlag = kFormEnum; delete[] mEnumValues; mEnumValues = new MtpPropertyValue[count]; mEnumLength = count; for (int i = 0; i < count; i++) { int value = *values++; switch (mType) { case MTP_TYPE_INT8: mEnumValues[i].u.i8 = value; break; case MTP_TYPE_UINT8: mEnumValues[i].u.u8 = value; break; case MTP_TYPE_INT16: mEnumValues[i].u.i16 = value; break; case MTP_TYPE_UINT16: mEnumValues[i].u.u16 = value; break; case MTP_TYPE_INT32: mEnumValues[i].u.i32 = value; break; case MTP_TYPE_UINT32: mEnumValues[i].u.u32 = value; break; case MTP_TYPE_INT64: mEnumValues[i].u.i64 = value; break; case MTP_TYPE_UINT64: mEnumValues[i].u.u64 = value; break; default: LOG(ERROR) << "unsupported type for MtpProperty::setEnum"; break; } } } void MtpProperty::setFormDateTime() { mFormFlag = kFormDateTime; } void MtpProperty::print() { MtpString buffer; bool deviceProp = isDeviceProperty(); if (deviceProp) VLOG(2) << MtpDebug::getDevicePropCodeName(mCode) << " (" << std::hex << mCode << std::dec << ")"; else VLOG(2) << MtpDebug::getObjectPropCodeName(mCode) << " (" << std::hex << mCode << std::dec << ")"; VLOG(2) << mType; VLOG(2) << "writeable " << (mWriteable ? "true" : "false"); buffer = "default value: "; print(mDefaultValue, buffer); VLOG(2) << buffer.c_str(); if (deviceProp) { buffer = "current value: "; print(mCurrentValue, buffer); VLOG(2) << buffer.c_str(); } switch (mFormFlag) { case kFormNone: break; case kFormRange: buffer = "Range ("; print(mMinimumValue, buffer); buffer += ", "; print(mMaximumValue, buffer); buffer += ", "; print(mStepSize, buffer); buffer += ")"; VLOG(2) << buffer.c_str(); break; case kFormEnum: buffer = "Enum { "; for (int i = 0; i < mEnumLength; i++) { print(mEnumValues[i], buffer); buffer += " "; } buffer += "}"; VLOG(2) << buffer.c_str(); break; case kFormDateTime: VLOG(2) << "DateTime"; break; default: VLOG(2) << "form " << mFormFlag; break; } } void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) { std::stringstream ss; switch (mType) { case MTP_TYPE_INT8: ss << value.u.i8; break; case MTP_TYPE_UINT8: ss << value.u.u8; break; case MTP_TYPE_INT16: ss << value.u.i16; break; case MTP_TYPE_UINT16: ss << value.u.u16; break; case MTP_TYPE_INT32: ss << value.u.i32; break; case MTP_TYPE_UINT32: ss << value.u.u32; break; case MTP_TYPE_INT64: ss << value.u.i64; break; case MTP_TYPE_UINT64: ss << value.u.u64; break; case MTP_TYPE_INT128: ss << std::hex << value.u.i128[0] << std::hex << value.u.i128[1] << std::hex << value.u.i128[2] << std::hex << value.u.i128[3]; //buffer.appendFormat("%08X%08X%08X%08X", value.u.i128[0], value.u.i128[1], // value.u.i128[2], value.u.i128[3]); break; case MTP_TYPE_UINT128: ss << std::hex << value.u.u128[0] << std::hex << value.u.u128[1] << std::hex << value.u.u128[2] << std::hex << value.u.u128[3]; // buffer.appendFormat("%08X%08X%08X%08X", value.u.u128[0], value.u.u128[1], // value.u.u128[2], value.u.u128[3]); break; case MTP_TYPE_STR: ss << value.str; break; default: LOG(ERROR) << "unsupported type for MtpProperty::print"; break; } buffer += ss.str(); } void MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) { MtpStringBuffer stringBuffer; switch (mType) { case MTP_TYPE_INT8: case MTP_TYPE_AINT8: value.u.i8 = packet.getInt8(); break; case MTP_TYPE_UINT8: case MTP_TYPE_AUINT8: value.u.u8 = packet.getUInt8(); break; case MTP_TYPE_INT16: case MTP_TYPE_AINT16: value.u.i16 = packet.getInt16(); break; case MTP_TYPE_UINT16: case MTP_TYPE_AUINT16: value.u.u16 = packet.getUInt16(); break; case MTP_TYPE_INT32: case MTP_TYPE_AINT32: value.u.i32 = packet.getInt32(); break; case MTP_TYPE_UINT32: case MTP_TYPE_AUINT32: value.u.u32 = packet.getUInt32(); break; case MTP_TYPE_INT64: case MTP_TYPE_AINT64: value.u.i64 = packet.getInt64(); break; case MTP_TYPE_UINT64: case MTP_TYPE_AUINT64: value.u.u64 = packet.getUInt64(); break; case MTP_TYPE_INT128: case MTP_TYPE_AINT128: packet.getInt128(value.u.i128); break; case MTP_TYPE_UINT128: case MTP_TYPE_AUINT128: packet.getUInt128(value.u.u128); break; case MTP_TYPE_STR: packet.getString(stringBuffer); value.str = strdup(stringBuffer); break; default: LOG(ERROR) << "unknown type " << std::hex << mType << std::dec << " in MtpProperty::readValue"; } } void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) { MtpStringBuffer stringBuffer; switch (mType) { case MTP_TYPE_INT8: case MTP_TYPE_AINT8: packet.putInt8(value.u.i8); break; case MTP_TYPE_UINT8: case MTP_TYPE_AUINT8: packet.putUInt8(value.u.u8); break; case MTP_TYPE_INT16: case MTP_TYPE_AINT16: packet.putInt16(value.u.i16); break; case MTP_TYPE_UINT16: case MTP_TYPE_AUINT16: packet.putUInt16(value.u.u16); break; case MTP_TYPE_INT32: case MTP_TYPE_AINT32: packet.putInt32(value.u.i32); break; case MTP_TYPE_UINT32: case MTP_TYPE_AUINT32: packet.putUInt32(value.u.u32); break; case MTP_TYPE_INT64: case MTP_TYPE_AINT64: packet.putInt64(value.u.i64); break; case MTP_TYPE_UINT64: case MTP_TYPE_AUINT64: packet.putUInt64(value.u.u64); break; case MTP_TYPE_INT128: case MTP_TYPE_AINT128: packet.putInt128(value.u.i128); break; case MTP_TYPE_UINT128: case MTP_TYPE_AUINT128: packet.putUInt128(value.u.u128); break; case MTP_TYPE_STR: if (value.str) packet.putString(value.str); else packet.putEmptyString(); break; default: LOG(ERROR) << "unknown type " << std::hex << mType << std::dec << " in MtpProperty::writeValue"; } } MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) { length = packet.getUInt32(); if (length == 0) return NULL; MtpPropertyValue* result = new MtpPropertyValue[length]; for (int i = 0; i < length; i++) readValue(packet, result[i]); return result; } void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length) { packet.putUInt32(length); for (int i = 0; i < length; i++) writeValue(packet, values[i]); } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpRequestPacket.cpp0000644000015301777760000000277612321133655021464 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpRequestPacket" #include #include #include #include #include "MtpRequestPacket.h" #include namespace android { MtpRequestPacket::MtpRequestPacket() : MtpPacket(512) { } MtpRequestPacket::~MtpRequestPacket() { } #ifdef MTP_DEVICE int MtpRequestPacket::read(int fd) { int ret = ::read(fd, mBuffer, mBufferSize); if (ret >= 0) mPacketSize = ret; else mPacketSize = 0; return ret; } #endif #ifdef MTP_HOST // write our buffer to the given endpoint (host mode) int MtpRequestPacket::write(struct usb_request *request) { putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_COMMAND); request->buffer = mBuffer; request->buffer_length = mPacketSize; return transfer(request); } #endif } // namespace android mtp-0.0.3+14.04.20140409/src/MtpPacket.cpp0000644000015301777760000001114012321133675020076 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpPacket" #include "MtpDebug.h" #include "MtpPacket.h" #include "mtp.h" #include #include #include #include #include namespace android { MtpPacket::MtpPacket(int bufferSize) : mBuffer(NULL), mBufferSize(bufferSize), mAllocationIncrement(bufferSize), mPacketSize(0) { mBuffer = (uint8_t *)malloc(bufferSize); if (!mBuffer) { LOG(FATAL) << "out of memory!"; } } MtpPacket::~MtpPacket() { if (mBuffer) free(mBuffer); } void MtpPacket::reset() { allocate(MTP_CONTAINER_HEADER_SIZE); mPacketSize = MTP_CONTAINER_HEADER_SIZE; memset(mBuffer, 0, mBufferSize); } void MtpPacket::allocate(int length) { if (length > mBufferSize) { int newLength = length + mAllocationIncrement; mBuffer = (uint8_t *)realloc(mBuffer, newLength); if (!mBuffer) { LOG(FATAL) << "out of memory!"; } mBufferSize = newLength; } } void MtpPacket::dump() { #define DUMP_BYTES_PER_ROW 16 char buffer[500]; char* bufptr = buffer; for (int i = 0; i < mPacketSize; i++) { sprintf(bufptr, "%02X ", mBuffer[i]); bufptr += strlen(bufptr); if (i % DUMP_BYTES_PER_ROW == (DUMP_BYTES_PER_ROW - 1)) { VLOG(3) << buffer; bufptr = buffer; } } if (bufptr != buffer) { // print last line VLOG(3) << buffer; } } void MtpPacket::copyFrom(const MtpPacket& src) { int length = src.mPacketSize; allocate(length); mPacketSize = length; memcpy(mBuffer, src.mBuffer, length); } uint16_t MtpPacket::getUInt16(int offset) const { return ((uint16_t)mBuffer[offset + 1] << 8) | (uint16_t)mBuffer[offset]; } uint32_t MtpPacket::getUInt32(int offset) const { return ((uint32_t)mBuffer[offset + 3] << 24) | ((uint32_t)mBuffer[offset + 2] << 16) | ((uint32_t)mBuffer[offset + 1] << 8) | (uint32_t)mBuffer[offset]; } void MtpPacket::putUInt16(int offset, uint16_t value) { mBuffer[offset++] = (uint8_t)(value & 0xFF); mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); } void MtpPacket::putUInt32(int offset, uint32_t value) { mBuffer[offset++] = (uint8_t)(value & 0xFF); mBuffer[offset++] = (uint8_t)((value >> 8) & 0xFF); mBuffer[offset++] = (uint8_t)((value >> 16) & 0xFF); mBuffer[offset++] = (uint8_t)((value >> 24) & 0xFF); } uint16_t MtpPacket::getContainerCode() const { return getUInt16(MTP_CONTAINER_CODE_OFFSET); } void MtpPacket::setContainerCode(uint16_t code) { putUInt16(MTP_CONTAINER_CODE_OFFSET, code); } uint16_t MtpPacket::getContainerType() const { return getUInt16(MTP_CONTAINER_TYPE_OFFSET); } MtpTransactionID MtpPacket::getTransactionID() const { return getUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET); } void MtpPacket::setTransactionID(MtpTransactionID id) { putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id); } uint32_t MtpPacket::getParameter(int index) const { if (index < 1 || index > 5) { LOG(ERROR) << "index " << index << " out of range in MtpPacket::getParameter"; return 0; } return getUInt32(MTP_CONTAINER_PARAMETER_OFFSET + (index - 1) * sizeof(uint32_t)); } void MtpPacket::setParameter(int index, uint32_t value) { if (index < 1 || index > 5) { LOG(ERROR) << "index " << index << " out of range in MtpPacket::setParameter"; return; } int offset = MTP_CONTAINER_PARAMETER_OFFSET + (index - 1) * sizeof(uint32_t); if (mPacketSize < offset + sizeof(uint32_t)) mPacketSize = offset + sizeof(uint32_t); putUInt32(offset, value); } #ifdef MTP_HOST int MtpPacket::transfer(struct usb_request* request) { int result = usb_device_bulk_transfer(request->dev, request->endpoint, request->buffer, request->buffer_length, 0); request->actual_length = result; return result; } #endif } // namespace android mtp-0.0.3+14.04.20140409/src/MtpEventPacket.cpp0000644000015301777760000000322212321133655021100 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpEventPacket" #include #include #include #include #include #ifdef MTP_DEVICE #include #endif #include "MtpEventPacket.h" #include namespace android { MtpEventPacket::MtpEventPacket() : MtpPacket(512) { } MtpEventPacket::~MtpEventPacket() { } #ifdef MTP_DEVICE int MtpEventPacket::write(int fd) { struct mtp_event event; putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_EVENT); event.data = mBuffer; event.length = mPacketSize; int ret = ::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event); return (ret < 0 ? ret : 0); } #endif #ifdef MTP_HOST int MtpEventPacket::read(struct usb_request *request) { request->buffer = mBuffer; request->buffer_length = mBufferSize; int ret = transfer(request); if (ret >= 0) mPacketSize = ret; else mPacketSize = 0; return ret; } #endif } // namespace android mtp-0.0.3+14.04.20140409/src/MtpDataPacket.cpp0000644000015301777760000003411012321133675020672 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "MtpDataPacket.h" #include "MtpStringBuffer.h" #define MTP_BUFFER_SIZE 16384 namespace android { MtpDataPacket::MtpDataPacket() : MtpPacket(MTP_BUFFER_SIZE), // MAX_USBFS_BUFFER_SIZE mOffset(MTP_CONTAINER_HEADER_SIZE) { } MtpDataPacket::~MtpDataPacket() { } void MtpDataPacket::reset() { MtpPacket::reset(); mOffset = MTP_CONTAINER_HEADER_SIZE; } void MtpDataPacket::setOperationCode(MtpOperationCode code) { MtpPacket::putUInt16(MTP_CONTAINER_CODE_OFFSET, code); } void MtpDataPacket::setTransactionID(MtpTransactionID id) { MtpPacket::putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id); } uint16_t MtpDataPacket::getUInt16() { int offset = mOffset; uint16_t result = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8); mOffset += 2; return result; } uint32_t MtpDataPacket::getUInt32() { int offset = mOffset; uint32_t result = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) | ((uint32_t)mBuffer[offset + 2] << 16) | ((uint32_t)mBuffer[offset + 3] << 24); mOffset += 4; return result; } uint64_t MtpDataPacket::getUInt64() { int offset = mOffset; uint64_t result = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) | ((uint64_t)mBuffer[offset + 2] << 16) | ((uint64_t)mBuffer[offset + 3] << 24) | ((uint64_t)mBuffer[offset + 4] << 32) | ((uint64_t)mBuffer[offset + 5] << 40) | ((uint64_t)mBuffer[offset + 6] << 48) | ((uint64_t)mBuffer[offset + 7] << 56); mOffset += 8; return result; } void MtpDataPacket::getUInt128(uint128_t& value) { value[0] = getUInt32(); value[1] = getUInt32(); value[2] = getUInt32(); value[3] = getUInt32(); } void MtpDataPacket::getString(MtpStringBuffer& string) { string.readFromPacket(this); } Int8List* MtpDataPacket::getAInt8() { Int8List* result = new Int8List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getInt8()); return result; } UInt8List* MtpDataPacket::getAUInt8() { UInt8List* result = new UInt8List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getUInt8()); return result; } Int16List* MtpDataPacket::getAInt16() { Int16List* result = new Int16List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getInt16()); return result; } UInt16List* MtpDataPacket::getAUInt16() { UInt16List* result = new UInt16List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getUInt16()); return result; } Int32List* MtpDataPacket::getAInt32() { Int32List* result = new Int32List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getInt32()); return result; } UInt32List* MtpDataPacket::getAUInt32() { UInt32List* result = new UInt32List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getUInt32()); return result; } Int64List* MtpDataPacket::getAInt64() { Int64List* result = new Int64List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getInt64()); return result; } UInt64List* MtpDataPacket::getAUInt64() { UInt64List* result = new UInt64List; int count = getUInt32(); for (int i = 0; i < count; i++) result->push_back(getUInt64()); return result; } void MtpDataPacket::putInt8(int8_t value) { allocate(mOffset + 1); mBuffer[mOffset++] = (uint8_t)value; if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putUInt8(uint8_t value) { allocate(mOffset + 1); mBuffer[mOffset++] = (uint8_t)value; if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putInt16(int16_t value) { allocate(mOffset + 2); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putUInt16(uint16_t value) { allocate(mOffset + 2); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putInt32(int32_t value) { allocate(mOffset + 4); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putUInt32(uint32_t value) { allocate(mOffset + 4); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putInt64(int64_t value) { allocate(mOffset + 8); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putUInt64(uint64_t value) { allocate(mOffset + 8); mBuffer[mOffset++] = (uint8_t)(value & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF); mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF); if (mPacketSize < mOffset) mPacketSize = mOffset; } void MtpDataPacket::putInt128(const int128_t& value) { putInt32(value[0]); putInt32(value[1]); putInt32(value[2]); putInt32(value[3]); } void MtpDataPacket::putUInt128(const uint128_t& value) { putUInt32(value[0]); putUInt32(value[1]); putUInt32(value[2]); putUInt32(value[3]); } void MtpDataPacket::putInt128(int64_t value) { putInt64(value); putInt64(value < 0 ? -1 : 0); } void MtpDataPacket::putUInt128(uint64_t value) { putUInt64(value); putUInt64(0); } void MtpDataPacket::putAInt8(const int8_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putInt8(*values++); } void MtpDataPacket::putAUInt8(const uint8_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putUInt8(*values++); } void MtpDataPacket::putAInt16(const int16_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putInt16(*values++); } void MtpDataPacket::putAUInt16(const uint16_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putUInt16(*values++); } void MtpDataPacket::putAUInt16(const UInt16List* values) { size_t count = (values ? values->size() : 0); putUInt32(count); for (size_t i = 0; i < count; i++) putUInt16((*values)[i]); } void MtpDataPacket::putAInt32(const int32_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putInt32(*values++); } void MtpDataPacket::putAUInt32(const uint32_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putUInt32(*values++); } void MtpDataPacket::putAUInt32(const UInt32List* list) { if (!list) { putEmptyArray(); } else { size_t size = list->size(); putUInt32(size); for (size_t i = 0; i < size; i++) putUInt32((*list)[i]); } } void MtpDataPacket::putAInt64(const int64_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putInt64(*values++); } void MtpDataPacket::putAUInt64(const uint64_t* values, int count) { putUInt32(count); for (int i = 0; i < count; i++) putUInt64(*values++); } void MtpDataPacket::putString(const MtpStringBuffer& string) { string.writeToPacket(this); } void MtpDataPacket::putString(const char* s) { MtpStringBuffer string(s); string.writeToPacket(this); } void MtpDataPacket::putString(const uint16_t* string) { int count = 0; for (int i = 0; i < 256; i++) { if (string[i]) count++; else break; } putUInt8(count > 0 ? count + 1 : 0); for (int i = 0; i < count; i++) putUInt16(string[i]); // only terminate with zero if string is not empty if (count > 0) putUInt16(0); } #ifdef MTP_DEVICE int MtpDataPacket::read(int fd) { int ret = ::read(fd, mBuffer, MTP_BUFFER_SIZE); if (ret < MTP_CONTAINER_HEADER_SIZE) return -1; mPacketSize = ret; mOffset = MTP_CONTAINER_HEADER_SIZE; return ret; } int MtpDataPacket::write(int fd) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); int ret = ::write(fd, mBuffer, mPacketSize); return (ret < 0 ? ret : 0); } int MtpDataPacket::writeData(int fd, void* data, uint32_t length) { allocate(length); memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length); length += MTP_CONTAINER_HEADER_SIZE; MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); int ret = ::write(fd, mBuffer, length); return (ret < 0 ? ret : 0); } #endif // MTP_DEVICE #ifdef MTP_HOST int MtpDataPacket::read(struct usb_request *request) { // first read the header request->buffer = mBuffer; request->buffer_length = mBufferSize; int length = transfer(request); if (length >= MTP_CONTAINER_HEADER_SIZE) { // look at the length field to see if the data spans multiple packets uint32_t totalLength = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); allocate(totalLength); while (totalLength > length) { request->buffer = mBuffer + length; request->buffer_length = totalLength - length; int ret = transfer(request); if (ret >= 0) length += ret; else { length = ret; break; } } } if (length >= 0) mPacketSize = length; return length; } int MtpDataPacket::readData(struct usb_request *request, void* buffer, int length) { int read = 0; while (read < length) { request->buffer = (char *)buffer + read; request->buffer_length = length - read; int ret = transfer(request); if (ret < 0) { return ret; } read += ret; } return read; } // Queue a read request. Call readDataWait to wait for result int MtpDataPacket::readDataAsync(struct usb_request *req) { if (usb_request_queue(req)) { PLOG(ERROR) << "usb_endpoint_queue failed"; return -1; } return 0; } // Wait for result of readDataAsync int MtpDataPacket::readDataWait(struct usb_device *device) { struct usb_request *req = usb_request_wait(device); return (req ? req->actual_length : -1); } int MtpDataPacket::readDataHeader(struct usb_request *request) { request->buffer = mBuffer; request->buffer_length = request->max_packet_size; int length = transfer(request); if (length >= 0) mPacketSize = length; return length; } int MtpDataPacket::writeDataHeader(struct usb_request *request, uint32_t length) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); request->buffer = mBuffer; request->buffer_length = MTP_CONTAINER_HEADER_SIZE; int ret = transfer(request); return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_request *request) { MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA); // send header separately from data request->buffer = mBuffer; request->buffer_length = MTP_CONTAINER_HEADER_SIZE; int ret = transfer(request); if (ret == MTP_CONTAINER_HEADER_SIZE) { request->buffer = mBuffer + MTP_CONTAINER_HEADER_SIZE; request->buffer_length = mPacketSize - MTP_CONTAINER_HEADER_SIZE; ret = transfer(request); } return (ret < 0 ? ret : 0); } int MtpDataPacket::write(struct usb_request *request, void* buffer, uint32_t length) { request->buffer = buffer; request->buffer_length = length; int ret = transfer(request); return (ret < 0 ? ret : 0); } #endif // MTP_HOST void* MtpDataPacket::getData(int& outLength) const { int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE; if (length > 0) { void* result = malloc(length); if (result) { memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length); outLength = length; return result; } } outLength = 0; return NULL; } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpDebug.cpp0000644000015301777760000005731712321133655017733 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "MtpDebug.h" namespace android { struct CodeEntry { const char* name; uint16_t code; }; static const CodeEntry sOperationCodes[] = { { "MTP_OPERATION_GET_DEVICE_INFO", 0x1001 }, { "MTP_OPERATION_OPEN_SESSION", 0x1002 }, { "MTP_OPERATION_CLOSE_SESSION", 0x1003 }, { "MTP_OPERATION_GET_STORAGE_IDS", 0x1004 }, { "MTP_OPERATION_GET_STORAGE_INFO", 0x1005 }, { "MTP_OPERATION_GET_NUM_OBJECTS", 0x1006 }, { "MTP_OPERATION_GET_OBJECT_HANDLES", 0x1007 }, { "MTP_OPERATION_GET_OBJECT_INFO", 0x1008 }, { "MTP_OPERATION_GET_OBJECT", 0x1009 }, { "MTP_OPERATION_GET_THUMB", 0x100A }, { "MTP_OPERATION_DELETE_OBJECT", 0x100B }, { "MTP_OPERATION_SEND_OBJECT_INFO", 0x100C }, { "MTP_OPERATION_SEND_OBJECT", 0x100D }, { "MTP_OPERATION_INITIATE_CAPTURE", 0x100E }, { "MTP_OPERATION_FORMAT_STORE", 0x100F }, { "MTP_OPERATION_RESET_DEVICE", 0x1010 }, { "MTP_OPERATION_SELF_TEST", 0x1011 }, { "MTP_OPERATION_SET_OBJECT_PROTECTION", 0x1012 }, { "MTP_OPERATION_POWER_DOWN", 0x1013 }, { "MTP_OPERATION_GET_DEVICE_PROP_DESC", 0x1014 }, { "MTP_OPERATION_GET_DEVICE_PROP_VALUE", 0x1015 }, { "MTP_OPERATION_SET_DEVICE_PROP_VALUE", 0x1016 }, { "MTP_OPERATION_RESET_DEVICE_PROP_VALUE", 0x1017 }, { "MTP_OPERATION_TERMINATE_OPEN_CAPTURE", 0x1018 }, { "MTP_OPERATION_MOVE_OBJECT", 0x1019 }, { "MTP_OPERATION_COPY_OBJECT", 0x101A }, { "MTP_OPERATION_GET_PARTIAL_OBJECT", 0x101B }, { "MTP_OPERATION_INITIATE_OPEN_CAPTURE", 0x101C }, { "MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED", 0x9801 }, { "MTP_OPERATION_GET_OBJECT_PROP_DESC", 0x9802 }, { "MTP_OPERATION_GET_OBJECT_PROP_VALUE", 0x9803 }, { "MTP_OPERATION_SET_OBJECT_PROP_VALUE", 0x9804 }, { "MTP_OPERATION_GET_OBJECT_PROP_LIST", 0x9805 }, { "MTP_OPERATION_SET_OBJECT_PROP_LIST", 0x9806 }, { "MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC", 0x9807 }, { "MTP_OPERATION_SEND_OBJECT_PROP_LIST", 0x9808 }, { "MTP_OPERATION_GET_OBJECT_REFERENCES", 0x9810 }, { "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 }, { "MTP_OPERATION_SKIP", 0x9820 }, // android extensions { "MTP_OPERATION_GET_PARTIAL_OBJECT_64", 0x95C1 }, { "MTP_OPERATION_SEND_PARTIAL_OBJECT", 0x95C2 }, { "MTP_OPERATION_TRUNCATE_OBJECT", 0x95C3 }, { "MTP_OPERATION_BEGIN_EDIT_OBJECT", 0x95C4 }, { "MTP_OPERATION_END_EDIT_OBJECT", 0x95C5 }, { 0, 0 }, }; static const CodeEntry sFormatCodes[] = { { "MTP_FORMAT_UNDEFINED", 0x3000 }, { "MTP_FORMAT_ASSOCIATION", 0x3001 }, { "MTP_FORMAT_SCRIPT", 0x3002 }, { "MTP_FORMAT_EXECUTABLE", 0x3003 }, { "MTP_FORMAT_TEXT", 0x3004 }, { "MTP_FORMAT_HTML", 0x3005 }, { "MTP_FORMAT_DPOF", 0x3006 }, { "MTP_FORMAT_AIFF", 0x3007 }, { "MTP_FORMAT_WAV", 0x3008 }, { "MTP_FORMAT_MP3", 0x3009 }, { "MTP_FORMAT_AVI", 0x300A }, { "MTP_FORMAT_MPEG", 0x300B }, { "MTP_FORMAT_ASF", 0x300C }, { "MTP_FORMAT_DEFINED", 0x3800 }, { "MTP_FORMAT_EXIF_JPEG", 0x3801 }, { "MTP_FORMAT_TIFF_EP", 0x3802 }, { "MTP_FORMAT_FLASHPIX", 0x3803 }, { "MTP_FORMAT_BMP", 0x3804 }, { "MTP_FORMAT_CIFF", 0x3805 }, { "MTP_FORMAT_GIF", 0x3807 }, { "MTP_FORMAT_JFIF", 0x3808 }, { "MTP_FORMAT_CD", 0x3809 }, { "MTP_FORMAT_PICT", 0x380A }, { "MTP_FORMAT_PNG", 0x380B }, { "MTP_FORMAT_TIFF", 0x380D }, { "MTP_FORMAT_TIFF_IT", 0x380E }, { "MTP_FORMAT_JP2", 0x380F }, { "MTP_FORMAT_JPX", 0x3810 }, { "MTP_FORMAT_UNDEFINED_FIRMWARE", 0xB802 }, { "MTP_FORMAT_WINDOWS_IMAGE_FORMAT", 0xB881 }, { "MTP_FORMAT_UNDEFINED_AUDIO", 0xB900 }, { "MTP_FORMAT_WMA", 0xB901 }, { "MTP_FORMAT_OGG", 0xB902 }, { "MTP_FORMAT_AAC", 0xB903 }, { "MTP_FORMAT_AUDIBLE", 0xB904 }, { "MTP_FORMAT_FLAC", 0xB906 }, { "MTP_FORMAT_UNDEFINED_VIDEO", 0xB980 }, { "MTP_FORMAT_WMV", 0xB981 }, { "MTP_FORMAT_MP4_CONTAINER", 0xB982 }, { "MTP_FORMAT_MP2", 0xB983 }, { "MTP_FORMAT_3GP_CONTAINER", 0xB984 }, { "MTP_FORMAT_UNDEFINED_COLLECTION", 0xBA00 }, { "MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM", 0xBA01 }, { "MTP_FORMAT_ABSTRACT_IMAGE_ALBUM", 0xBA02 }, { "MTP_FORMAT_ABSTRACT_AUDIO_ALBUM", 0xBA03 }, { "MTP_FORMAT_ABSTRACT_VIDEO_ALBUM", 0xBA04 }, { "MTP_FORMAT_ABSTRACT_AV_PLAYLIST", 0xBA05 }, { "MTP_FORMAT_ABSTRACT_CONTACT_GROUP", 0xBA06 }, { "MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER", 0xBA07 }, { "MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION", 0xBA08 }, { "MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST", 0xBA09 }, { "MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST", 0xBA0A }, { "MTP_FORMAT_ABSTRACT_MEDIACAST", 0xBA0B }, { "MTP_FORMAT_WPL_PLAYLIST", 0xBA10 }, { "MTP_FORMAT_M3U_PLAYLIST", 0xBA11 }, { "MTP_FORMAT_MPL_PLAYLIST", 0xBA12 }, { "MTP_FORMAT_ASX_PLAYLIST", 0xBA13 }, { "MTP_FORMAT_PLS_PLAYLIST", 0xBA14 }, { "MTP_FORMAT_UNDEFINED_DOCUMENT", 0xBA80 }, { "MTP_FORMAT_ABSTRACT_DOCUMENT", 0xBA81 }, { "MTP_FORMAT_XML_DOCUMENT", 0xBA82 }, { "MTP_FORMAT_MS_WORD_DOCUMENT", 0xBA83 }, { "MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT", 0xBA84 }, { "MTP_FORMAT_MS_EXCEL_SPREADSHEET", 0xBA85 }, { "MTP_FORMAT_MS_POWERPOINT_PRESENTATION", 0xBA86 }, { "MTP_FORMAT_UNDEFINED_MESSAGE", 0xBB00 }, { "MTP_FORMAT_ABSTRACT_MESSSAGE", 0xBB01 }, { "MTP_FORMAT_UNDEFINED_CONTACT", 0xBB80 }, { "MTP_FORMAT_ABSTRACT_CONTACT", 0xBB81 }, { "MTP_FORMAT_VCARD_2", 0xBB82 }, { 0, 0 }, }; static const CodeEntry sObjectPropCodes[] = { { "MTP_PROPERTY_STORAGE_ID", 0xDC01 }, { "MTP_PROPERTY_OBJECT_FORMAT", 0xDC02 }, { "MTP_PROPERTY_PROTECTION_STATUS", 0xDC03 }, { "MTP_PROPERTY_OBJECT_SIZE", 0xDC04 }, { "MTP_PROPERTY_ASSOCIATION_TYPE", 0xDC05 }, { "MTP_PROPERTY_ASSOCIATION_DESC", 0xDC06 }, { "MTP_PROPERTY_OBJECT_FILE_NAME", 0xDC07 }, { "MTP_PROPERTY_DATE_CREATED", 0xDC08 }, { "MTP_PROPERTY_DATE_MODIFIED", 0xDC09 }, { "MTP_PROPERTY_KEYWORDS", 0xDC0A }, { "MTP_PROPERTY_PARENT_OBJECT", 0xDC0B }, { "MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS", 0xDC0C }, { "MTP_PROPERTY_HIDDEN", 0xDC0D }, { "MTP_PROPERTY_SYSTEM_OBJECT", 0xDC0E }, { "MTP_PROPERTY_PERSISTENT_UID", 0xDC41 }, { "MTP_PROPERTY_SYNC_ID", 0xDC42 }, { "MTP_PROPERTY_PROPERTY_BAG", 0xDC43 }, { "MTP_PROPERTY_NAME", 0xDC44 }, { "MTP_PROPERTY_CREATED_BY", 0xDC45 }, { "MTP_PROPERTY_ARTIST", 0xDC46 }, { "MTP_PROPERTY_DATE_AUTHORED", 0xDC47 }, { "MTP_PROPERTY_DESCRIPTION", 0xDC48 }, { "MTP_PROPERTY_URL_REFERENCE", 0xDC49 }, { "MTP_PROPERTY_LANGUAGE_LOCALE", 0xDC4A }, { "MTP_PROPERTY_COPYRIGHT_INFORMATION", 0xDC4B }, { "MTP_PROPERTY_SOURCE", 0xDC4C }, { "MTP_PROPERTY_ORIGIN_LOCATION", 0xDC4D }, { "MTP_PROPERTY_DATE_ADDED", 0xDC4E }, { "MTP_PROPERTY_NON_CONSUMABLE", 0xDC4F }, { "MTP_PROPERTY_CORRUPT_UNPLAYABLE", 0xDC50 }, { "MTP_PROPERTY_PRODUCER_SERIAL_NUMBER", 0xDC51 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT", 0xDC81 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE", 0xDC82 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT", 0xDC83 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH", 0xDC84 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION", 0xDC85 }, { "MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA", 0xDC86 }, { "MTP_PROPERTY_WIDTH", 0xDC87 }, { "MTP_PROPERTY_HEIGHT", 0xDC88 }, { "MTP_PROPERTY_DURATION", 0xDC89 }, { "MTP_PROPERTY_RATING", 0xDC8A }, { "MTP_PROPERTY_TRACK", 0xDC8B }, { "MTP_PROPERTY_GENRE", 0xDC8C }, { "MTP_PROPERTY_CREDITS", 0xDC8D }, { "MTP_PROPERTY_LYRICS", 0xDC8E }, { "MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID", 0xDC8F }, { "MTP_PROPERTY_PRODUCED_BY", 0xDC90 }, { "MTP_PROPERTY_USE_COUNT", 0xDC91 }, { "MTP_PROPERTY_SKIP_COUNT", 0xDC92 }, { "MTP_PROPERTY_LAST_ACCESSED", 0xDC93 }, { "MTP_PROPERTY_PARENTAL_RATING", 0xDC94 }, { "MTP_PROPERTY_META_GENRE", 0xDC95 }, { "MTP_PROPERTY_COMPOSER", 0xDC96 }, { "MTP_PROPERTY_EFFECTIVE_RATING", 0xDC97 }, { "MTP_PROPERTY_SUBTITLE", 0xDC98 }, { "MTP_PROPERTY_ORIGINAL_RELEASE_DATE", 0xDC99 }, { "MTP_PROPERTY_ALBUM_NAME", 0xDC9A }, { "MTP_PROPERTY_ALBUM_ARTIST", 0xDC9B }, { "MTP_PROPERTY_MOOD", 0xDC9C }, { "MTP_PROPERTY_DRM_STATUS", 0xDC9D }, { "MTP_PROPERTY_SUB_DESCRIPTION", 0xDC9E }, { "MTP_PROPERTY_IS_CROPPED", 0xDCD1 }, { "MTP_PROPERTY_IS_COLOUR_CORRECTED", 0xDCD2 }, { "MTP_PROPERTY_IMAGE_BIT_DEPTH", 0xDCD3 }, { "MTP_PROPERTY_F_NUMBER", 0xDCD4 }, { "MTP_PROPERTY_EXPOSURE_TIME", 0xDCD5 }, { "MTP_PROPERTY_EXPOSURE_INDEX", 0xDCD6 }, { "MTP_PROPERTY_TOTAL_BITRATE", 0xDE91 }, { "MTP_PROPERTY_BITRATE_TYPE", 0xDE92 }, { "MTP_PROPERTY_SAMPLE_RATE", 0xDE93 }, { "MTP_PROPERTY_NUMBER_OF_CHANNELS", 0xDE94 }, { "MTP_PROPERTY_AUDIO_BIT_DEPTH", 0xDE95 }, { "MTP_PROPERTY_SCAN_TYPE", 0xDE97 }, { "MTP_PROPERTY_AUDIO_WAVE_CODEC", 0xDE99 }, { "MTP_PROPERTY_AUDIO_BITRATE", 0xDE9A }, { "MTP_PROPERTY_VIDEO_FOURCC_CODEC", 0xDE9B }, { "MTP_PROPERTY_VIDEO_BITRATE", 0xDE9C }, { "MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS", 0xDE9D }, { "MTP_PROPERTY_KEYFRAME_DISTANCE", 0xDE9E }, { "MTP_PROPERTY_BUFFER_SIZE", 0xDE9F }, { "MTP_PROPERTY_ENCODING_QUALITY", 0xDEA0 }, { "MTP_PROPERTY_ENCODING_PROFILE", 0xDEA1 }, { "MTP_PROPERTY_DISPLAY_NAME", 0xDCE0 }, { "MTP_PROPERTY_BODY_TEXT", 0xDCE1 }, { "MTP_PROPERTY_SUBJECT", 0xDCE2 }, { "MTP_PROPERTY_PRIORITY", 0xDCE3 }, { "MTP_PROPERTY_GIVEN_NAME", 0xDD00 }, { "MTP_PROPERTY_MIDDLE_NAMES", 0xDD01 }, { "MTP_PROPERTY_FAMILY_NAME", 0xDD02 }, { "MTP_PROPERTY_PREFIX", 0xDD03 }, { "MTP_PROPERTY_SUFFIX", 0xDD04 }, { "MTP_PROPERTY_PHONETIC_GIVEN_NAME", 0xDD05 }, { "MTP_PROPERTY_PHONETIC_FAMILY_NAME", 0xDD06 }, { "MTP_PROPERTY_EMAIL_PRIMARY", 0xDD07 }, { "MTP_PROPERTY_EMAIL_PERSONAL_1", 0xDD08 }, { "MTP_PROPERTY_EMAIL_PERSONAL_2", 0xDD09 }, { "MTP_PROPERTY_EMAIL_BUSINESS_1", 0xDD0A }, { "MTP_PROPERTY_EMAIL_BUSINESS_2", 0xDD0B }, { "MTP_PROPERTY_EMAIL_OTHERS", 0xDD0C }, { "MTP_PROPERTY_PHONE_NUMBER_PRIMARY", 0xDD0D }, { "MTP_PROPERTY_PHONE_NUMBER_PERSONAL", 0xDD0E }, { "MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2", 0xDD0F }, { "MTP_PROPERTY_PHONE_NUMBER_BUSINESS", 0xDD10 }, { "MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2", 0xDD11 }, { "MTP_PROPERTY_PHONE_NUMBER_MOBILE", 0xDD12 }, { "MTP_PROPERTY_PHONE_NUMBER_MOBILE_2", 0xDD13 }, { "MTP_PROPERTY_FAX_NUMBER_PRIMARY", 0xDD14 }, { "MTP_PROPERTY_FAX_NUMBER_PERSONAL", 0xDD15 }, { "MTP_PROPERTY_FAX_NUMBER_BUSINESS", 0xDD16 }, { "MTP_PROPERTY_PAGER_NUMBER", 0xDD17 }, { "MTP_PROPERTY_PHONE_NUMBER_OTHERS", 0xDD18 }, { "MTP_PROPERTY_PRIMARY_WEB_ADDRESS", 0xDD19 }, { "MTP_PROPERTY_PERSONAL_WEB_ADDRESS", 0xDD1A }, { "MTP_PROPERTY_BUSINESS_WEB_ADDRESS", 0xDD1B }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS", 0xDD1C }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2", 0xDD1D }, { "MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3", 0xDD1E }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL", 0xDD1F }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1", 0xDD20 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2", 0xDD21 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY", 0xDD22 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION", 0xDD23 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE", 0xDD24 }, { "MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY", 0xDD25 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL", 0xDD26 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1", 0xDD27 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2", 0xDD28 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY", 0xDD29 }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION", 0xDD2A }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE", 0xDD2B }, { "MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY", 0xDD2C }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL", 0xDD2D }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1", 0xDD2E }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2", 0xDD2F }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY", 0xDD30 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION", 0xDD31 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE", 0xDD32 }, { "MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY", 0xDD33 }, { "MTP_PROPERTY_ORGANIZATION_NAME", 0xDD34 }, { "MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME", 0xDD35 }, { "MTP_PROPERTY_ROLE", 0xDD36 }, { "MTP_PROPERTY_BIRTHDATE", 0xDD37 }, { "MTP_PROPERTY_MESSAGE_TO", 0xDD40 }, { "MTP_PROPERTY_MESSAGE_CC", 0xDD41 }, { "MTP_PROPERTY_MESSAGE_BCC", 0xDD42 }, { "MTP_PROPERTY_MESSAGE_READ", 0xDD43 }, { "MTP_PROPERTY_MESSAGE_RECEIVED_TIME", 0xDD44 }, { "MTP_PROPERTY_MESSAGE_SENDER", 0xDD45 }, { "MTP_PROPERTY_ACTIVITY_BEGIN_TIME", 0xDD50 }, { "MTP_PROPERTY_ACTIVITY_END_TIME", 0xDD51 }, { "MTP_PROPERTY_ACTIVITY_LOCATION", 0xDD52 }, { "MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES", 0xDD54 }, { "MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES", 0xDD55 }, { "MTP_PROPERTY_ACTIVITY_RESOURCES", 0xDD56 }, { "MTP_PROPERTY_ACTIVITY_ACCEPTED", 0xDD57 }, { "MTP_PROPERTY_ACTIVITY_TENTATIVE", 0xDD58 }, { "MTP_PROPERTY_ACTIVITY_DECLINED", 0xDD59 }, { "MTP_PROPERTY_ACTIVITY_REMAINDER_TIME", 0xDD5A }, { "MTP_PROPERTY_ACTIVITY_OWNER", 0xDD5B }, { "MTP_PROPERTY_ACTIVITY_STATUS", 0xDD5C }, { "MTP_PROPERTY_OWNER", 0xDD5D }, { "MTP_PROPERTY_EDITOR", 0xDD5E }, { "MTP_PROPERTY_WEBMASTER", 0xDD5F }, { "MTP_PROPERTY_URL_SOURCE", 0xDD60 }, { "MTP_PROPERTY_URL_DESTINATION", 0xDD61 }, { "MTP_PROPERTY_TIME_BOOKMARK", 0xDD62 }, { "MTP_PROPERTY_OBJECT_BOOKMARK", 0xDD63 }, { "MTP_PROPERTY_BYTE_BOOKMARK", 0xDD64 }, { "MTP_PROPERTY_LAST_BUILD_DATE", 0xDD70 }, { "MTP_PROPERTY_TIME_TO_LIVE", 0xDD71 }, { "MTP_PROPERTY_MEDIA_GUID", 0xDD72 }, { 0, 0 }, }; static const CodeEntry sDevicePropCodes[] = { { "MTP_DEVICE_PROPERTY_UNDEFINED", 0x5000 }, { "MTP_DEVICE_PROPERTY_BATTERY_LEVEL", 0x5001 }, { "MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE", 0x5002 }, { "MTP_DEVICE_PROPERTY_IMAGE_SIZE", 0x5003 }, { "MTP_DEVICE_PROPERTY_COMPRESSION_SETTING", 0x5004 }, { "MTP_DEVICE_PROPERTY_WHITE_BALANCE", 0x5005 }, { "MTP_DEVICE_PROPERTY_RGB_GAIN", 0x5006 }, { "MTP_DEVICE_PROPERTY_F_NUMBER", 0x5007 }, { "MTP_DEVICE_PROPERTY_FOCAL_LENGTH", 0x5008 }, { "MTP_DEVICE_PROPERTY_FOCUS_DISTANCE", 0x5009 }, { "MTP_DEVICE_PROPERTY_FOCUS_MODE", 0x500A }, { "MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE", 0x500B }, { "MTP_DEVICE_PROPERTY_FLASH_MODE", 0x500C }, { "MTP_DEVICE_PROPERTY_EXPOSURE_TIME", 0x500D }, { "MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE", 0x500E }, { "MTP_DEVICE_PROPERTY_EXPOSURE_INDEX", 0x500F }, { "MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION", 0x5010 }, { "MTP_DEVICE_PROPERTY_DATETIME", 0x5011 }, { "MTP_DEVICE_PROPERTY_CAPTURE_DELAY", 0x5012 }, { "MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE", 0x5013 }, { "MTP_DEVICE_PROPERTY_CONTRAST", 0x5014 }, { "MTP_DEVICE_PROPERTY_SHARPNESS", 0x5015 }, { "MTP_DEVICE_PROPERTY_DIGITAL_ZOOM", 0x5016 }, { "MTP_DEVICE_PROPERTY_EFFECT_MODE", 0x5017 }, { "MTP_DEVICE_PROPERTY_BURST_NUMBER", 0x5018 }, { "MTP_DEVICE_PROPERTY_BURST_INTERVAL", 0x5019 }, { "MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER", 0x501A }, { "MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL", 0x501B }, { "MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE", 0x501C }, { "MTP_DEVICE_PROPERTY_UPLOAD_URL", 0x501D }, { "MTP_DEVICE_PROPERTY_ARTIST", 0x501E }, { "MTP_DEVICE_PROPERTY_COPYRIGHT_INFO", 0x501F }, { "MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER", 0xD401 }, { "MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME", 0xD402 }, { "MTP_DEVICE_PROPERTY_VOLUME", 0xD403 }, { "MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED", 0xD404 }, { "MTP_DEVICE_PROPERTY_DEVICE_ICON", 0xD405 }, { "MTP_DEVICE_PROPERTY_PLAYBACK_RATE", 0xD410 }, { "MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT", 0xD411 }, { "MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX", 0xD412 }, { "MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO", 0xD406 }, { "MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE", 0xD407 }, { 0, 0 }, }; static const char* getCodeName(uint16_t code, const CodeEntry* table) { const CodeEntry* entry = table; while (entry->name) { if (entry->code == code) return entry->name; entry++; } return "UNKNOWN"; } const char* MtpDebug::getOperationCodeName(MtpOperationCode code) { return getCodeName(code, sOperationCodes); } const char* MtpDebug::getFormatCodeName(MtpObjectFormat code) { if (code == 0) return "NONE"; return getCodeName(code, sFormatCodes); } const char* MtpDebug::getObjectPropCodeName(MtpPropertyCode code) { if (code == 0) return "NONE"; return getCodeName(code, sObjectPropCodes); } const char* MtpDebug::getDevicePropCodeName(MtpPropertyCode code) { if (code == 0) return "NONE"; return getCodeName(code, sDevicePropCodes); } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpDevice.cpp0000644000015301777760000006505712321133675020106 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpDevice" #include "MtpDebug.h" #include "MtpDevice.h" #include "MtpDeviceInfo.h" #include "MtpObjectInfo.h" #include "MtpProperty.h" #include "MtpStorageInfo.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { #if 0 static bool isMtpDevice(uint16_t vendor, uint16_t product) { // Sandisk Sansa Fuze if (vendor == 0x0781 && product == 0x74c2) return true; // Samsung YP-Z5 if (vendor == 0x04e8 && product == 0x503c) return true; return false; } #endif MtpDevice* MtpDevice::open(const char* deviceName, int fd) { struct usb_device *device = usb_device_new(deviceName, fd); if (!device) { LOG(ERROR) << "usb_device_new failed for " << deviceName; return NULL; } struct usb_descriptor_header* desc; struct usb_descriptor_iter iter; usb_descriptor_iter_init(device, &iter); while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { if (desc->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && interface->bInterfaceSubClass == 1 && // Still Image Capture interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) { char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); VLOG(2) << "Found camera: \"" << manufacturerName << " \"" << productName << "\""; free(manufacturerName); free(productName); } else if (interface->bInterfaceClass == 0xFF && interface->bInterfaceSubClass == 0xFF && interface->bInterfaceProtocol == 0) { char* interfaceName = usb_device_get_string(device, interface->iInterface); if (!interfaceName) { continue; } else if (strcmp(interfaceName, "MTP")) { free(interfaceName); continue; } free(interfaceName); // Looks like an android style MTP device char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); VLOG(2) << "Found MTP device: \"" << manufacturerName << "\" \"" << productName << "\""; free(manufacturerName); free(productName); } #if 0 else { // look for special cased devices based on vendor/product ID // we are doing this mainly for testing purposes uint16_t vendor = usb_device_get_vendor_id(device); uint16_t product = usb_device_get_product_id(device); if (!isMtpDevice(vendor, product)) { // not an MTP or PTP device continue; } // request MTP OS string and descriptor // some music players need to see this before entering MTP mode. char buffer[256]; memset(buffer, 0, sizeof(buffer)); int ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE, 0, buffer, sizeof(buffer), 0); printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno); if (ret > 0) { printf("got MTP string %s\n", buffer); ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1, 0, 4, buffer, sizeof(buffer), 0); printf("OS descriptor got %d\n", ret); } else { printf("no MTP string\n"); } } #endif // if we got here, then we have a likely MTP or PTP device // interface should be followed by three endpoints struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in_desc = NULL; struct usb_endpoint_descriptor *ep_out_desc = NULL; struct usb_endpoint_descriptor *ep_intr_desc = NULL; for (int i = 0; i < 3; i++) { ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { LOG(ERROR) << "endpoints not found"; usb_device_close(device); return NULL; } if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ep_in_desc = ep; else ep_out_desc = ep; } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { ep_intr_desc = ep; } } if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { LOG(ERROR) << "endpoints not found"; usb_device_close(device); return NULL; } if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { PLOG(ERROR) << "usb_device_claim_interface failed"; usb_device_close(device); return NULL; } MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, ep_in_desc, ep_out_desc, ep_intr_desc); mtpDevice->initialize(); return mtpDevice; } } usb_device_close(device); LOG(ERROR) << "device not found"; return NULL; } MtpDevice::MtpDevice(struct usb_device* device, int interface, const struct usb_endpoint_descriptor *ep_in, const struct usb_endpoint_descriptor *ep_out, const struct usb_endpoint_descriptor *ep_intr) : mDevice(device), mInterface(interface), mRequestIn1(NULL), mRequestIn2(NULL), mRequestOut(NULL), mRequestIntr(NULL), mDeviceInfo(NULL), mSessionID(0), mTransactionID(0), mReceivedResponse(false) { mRequestIn1 = usb_request_new(device, ep_in); mRequestIn2 = usb_request_new(device, ep_in); mRequestOut = usb_request_new(device, ep_out); mRequestIntr = usb_request_new(device, ep_intr); } MtpDevice::~MtpDevice() { close(); for (int i = 0; i < mDeviceProperties.size(); i++) delete mDeviceProperties[i]; usb_request_free(mRequestIn1); usb_request_free(mRequestIn2); usb_request_free(mRequestOut); usb_request_free(mRequestIntr); } void MtpDevice::initialize() { openSession(); mDeviceInfo = getDeviceInfo(); if (mDeviceInfo) { if (mDeviceInfo->mDeviceProperties) { int count = mDeviceInfo->mDeviceProperties->size(); for (int i = 0; i < count; i++) { MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; MtpProperty* property = getDevicePropDesc(propCode); if (property) mDeviceProperties.push_back(property); } } } } void MtpDevice::close() { if (mDevice) { usb_device_release_interface(mDevice, mInterface); usb_device_close(mDevice); mDevice = NULL; } } void MtpDevice::print() { if (mDeviceInfo) { mDeviceInfo->print(); if (mDeviceInfo->mDeviceProperties) { VLOG(2) << "***** DEVICE PROPERTIES *****"; int count = mDeviceInfo->mDeviceProperties->size(); for (int i = 0; i < count; i++) { MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; MtpProperty* property = getDevicePropDesc(propCode); if (property) { property->print(); delete property; } } } } if (mDeviceInfo->mPlaybackFormats) { VLOG(2) << "***** OBJECT PROPERTIES *****"; int count = mDeviceInfo->mPlaybackFormats->size(); for (int i = 0; i < count; i++) { MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i]; VLOG(2) << "*** FORMAT: " << MtpDebug::getFormatCodeName(format); MtpObjectPropertyList* props = getObjectPropsSupported(format); if (props) { for (int j = 0; j < props->size(); j++) { MtpObjectProperty prop = (*props)[j]; MtpProperty* property = getObjectPropDesc(prop, format); if (property) { property->print(); delete property; } else { LOG(ERROR) << "could not fetch property: " << MtpDebug::getObjectPropCodeName(prop); } } } } } } const char* MtpDevice::getDeviceName() { if (mDevice) return usb_device_get_name(mDevice); else return "???"; } bool MtpDevice::openSession() { MtpAutolock autoLock(mMutex); mSessionID = 0; mTransactionID = 0; MtpSessionID newSession = 1; mRequest.reset(); mRequest.setParameter(1, newSession); if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) return false; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) newSession = mResponse.getParameter(1); else if (ret != MTP_RESPONSE_OK) return false; mSessionID = newSession; mTransactionID = 1; return true; } bool MtpDevice::closeSession() { // FIXME return true; } MtpDeviceInfo* MtpDevice::getDeviceInfo() { MtpAutolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpDeviceInfo* info = new MtpDeviceInfo; info->read(mData); return info; } return NULL; } MtpStorageIDList* MtpDevice::getStorageIDs() { MtpAutolock autoLock(mMutex); mRequest.reset(); if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { return mData.getAUInt32(); } return NULL; } MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpStorageInfo* info = new MtpStorageInfo(storageID); info->read(mData); return info; } return NULL; } MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, storageID); mRequest.setParameter(2, format); mRequest.setParameter(3, parent); if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { return mData.getAUInt32(); } return NULL; } MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { MtpAutolock autoLock(mMutex); // FIXME - we might want to add some caching here mRequest.reset(); mRequest.setParameter(1, handle); if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpObjectInfo* info = new MtpObjectInfo(handle); info->read(mData); return info; } return NULL; } void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { return mData.getData(outLength); } } outLength = 0; return NULL; } MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { MtpAutolock autoLock(mMutex); mRequest.reset(); MtpObjectHandle parent = info->mParent; if (parent == 0) parent = MTP_PARENT_ROOT; mRequest.setParameter(1, info->mStorageID); mRequest.setParameter(2, info->mParent); mData.putUInt32(info->mStorageID); mData.putUInt16(info->mFormat); mData.putUInt16(info->mProtectionStatus); mData.putUInt32(info->mCompressedSize); mData.putUInt16(info->mThumbFormat); mData.putUInt32(info->mThumbCompressedSize); mData.putUInt32(info->mThumbPixWidth); mData.putUInt32(info->mThumbPixHeight); mData.putUInt32(info->mImagePixWidth); mData.putUInt32(info->mImagePixHeight); mData.putUInt32(info->mImagePixDepth); mData.putUInt32(info->mParent); mData.putUInt16(info->mAssociationType); mData.putUInt32(info->mAssociationDesc); mData.putUInt32(info->mSequenceNumber); mData.putString(info->mName); char created[100], modified[100]; formatDateTime(info->mDateCreated, created, sizeof(created)); formatDateTime(info->mDateModified, modified, sizeof(modified)); mData.putString(created); mData.putString(modified); if (info->mKeywords) mData.putString(info->mKeywords); else mData.putEmptyString(); if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { info->mStorageID = mResponse.getParameter(1); info->mParent = mResponse.getParameter(2); info->mHandle = mResponse.getParameter(3); return info->mHandle; } } return (MtpObjectHandle)-1; } bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { MtpAutolock autoLock(mMutex); int remaining = info->mCompressedSize; mRequest.reset(); mRequest.setParameter(1, info->mHandle); if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { // send data header writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); char buffer[65536]; while (remaining > 0) { int count = read(srcFD, buffer, sizeof(buffer)); if (count > 0) { int written = mData.write(mRequestOut, buffer, count); // FIXME check error remaining -= count; } else { break; } } } MtpResponseCode ret = readResponse(); return (remaining == 0 && ret == MTP_RESPONSE_OK); } bool MtpDevice::deleteObject(MtpObjectHandle handle) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) return true; } return false; } MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) { MtpObjectInfo* info = getObjectInfo(handle); if (info) { MtpObjectHandle parent = info->mParent; delete info; return parent; } else { return -1; } } MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { MtpObjectInfo* info = getObjectInfo(handle); if (info) { MtpObjectHandle storageId = info->mStorageID; delete info; return storageId; } else { return -1; } } MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, format); if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { return mData.getAUInt16(); } return NULL; } MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, code); if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpProperty* property = new MtpProperty; property->read(mData); return property; } return NULL; } MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) { MtpAutolock autoLock(mMutex); mRequest.reset(); mRequest.setParameter(1, code); mRequest.setParameter(2, format); if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC)) return NULL; if (!readData()) return NULL; MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpProperty* property = new MtpProperty; property->read(mData); return property; } return NULL; } bool MtpDevice::readObject(MtpObjectHandle handle, bool (* callback)(void* data, int offset, int length, void* clientData), int objectSize, void* clientData) { MtpAutolock autoLock(mMutex); bool result = false; mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_GET_OBJECT) && mData.readDataHeader(mRequestIn1)) { uint32_t length = mData.getContainerLength(); if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) { LOG(ERROR) << "readObject error objectSize: " << objectSize << " length: " << length; goto fail; } length -= MTP_CONTAINER_HEADER_SIZE; uint32_t remaining = length; int offset = 0; int initialDataLength = 0; void* initialData = mData.getData(initialDataLength); if (initialData) { if (initialDataLength > 0) { if (!callback(initialData, 0, initialDataLength, clientData)) goto fail; remaining -= initialDataLength; offset += initialDataLength; } free(initialData); } // USB reads greater than 16K don't work char buffer1[16384], buffer2[16384]; mRequestIn1->buffer = buffer1; mRequestIn2->buffer = buffer2; struct usb_request* req = mRequestIn1; void* writeBuffer = NULL; int writeLength = 0; while (remaining > 0 || writeBuffer) { if (remaining > 0) { // queue up a read request req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); if (mData.readDataAsync(req)) { LOG(ERROR) << "readDataAsync failed"; goto fail; } } else { req = NULL; } if (writeBuffer) { // write previous buffer if (!callback(writeBuffer, offset, writeLength, clientData)) { LOG(ERROR) << "write failed"; // wait for pending read before failing if (req) mData.readDataWait(mDevice); goto fail; } offset += writeLength; writeBuffer = NULL; } // wait for read to complete if (req) { int read = mData.readDataWait(mDevice); if (read < 0) goto fail; if (read > 0) { writeBuffer = req->buffer; writeLength = read; remaining -= read; req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); } else { writeBuffer = NULL; } } } MtpResponseCode response = readResponse(); if (response == MTP_RESPONSE_OK) result = true; } fail: return result; } // reads the object's data and writes it to the specified file path bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) { VLOG(2) << "readObject: " << destPath; int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { LOG(ERROR) << "open failed for " << destPath; return false; } fchown(fd, getuid(), group); // set permissions int mask = umask(0); fchmod(fd, perm); umask(mask); MtpAutolock autoLock(mMutex); bool result = false; mRequest.reset(); mRequest.setParameter(1, handle); if (sendRequest(MTP_OPERATION_GET_OBJECT) && mData.readDataHeader(mRequestIn1)) { uint32_t length = mData.getContainerLength(); if (length < MTP_CONTAINER_HEADER_SIZE) goto fail; length -= MTP_CONTAINER_HEADER_SIZE; uint32_t remaining = length; int initialDataLength = 0; void* initialData = mData.getData(initialDataLength); if (initialData) { if (initialDataLength > 0) { if (write(fd, initialData, initialDataLength) != initialDataLength) { free(initialData); goto fail; } remaining -= initialDataLength; } free(initialData); } // USB reads greater than 16K don't work char buffer1[16384], buffer2[16384]; mRequestIn1->buffer = buffer1; mRequestIn2->buffer = buffer2; struct usb_request* req = mRequestIn1; void* writeBuffer = NULL; int writeLength = 0; while (remaining > 0 || writeBuffer) { if (remaining > 0) { // queue up a read request req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); if (mData.readDataAsync(req)) { LOG(ERROR) << "readDataAsync failed"; goto fail; } } else { req = NULL; } if (writeBuffer) { // write previous buffer if (write(fd, writeBuffer, writeLength) != writeLength) { LOG(ERROR) << "write failed"; // wait for pending read before failing if (req) mData.readDataWait(mDevice); goto fail; } writeBuffer = NULL; } // wait for read to complete if (req) { int read = mData.readDataWait(mDevice); if (read < 0) goto fail; if (read > 0) { writeBuffer = req->buffer; writeLength = read; remaining -= read; req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); } else { writeBuffer = NULL; } } } MtpResponseCode response = readResponse(); if (response == MTP_RESPONSE_OK) result = true; } fail: ::close(fd); return result; } bool MtpDevice::sendRequest(MtpOperationCode operation) { VLOG(2) << "sendRequest: " << MtpDebug::getOperationCodeName(operation); mReceivedResponse = false; mRequest.setOperationCode(operation); if (mTransactionID > 0) mRequest.setTransactionID(mTransactionID++); int ret = mRequest.write(mRequestOut); mRequest.dump(); return (ret > 0); } bool MtpDevice::sendData() { VLOG(2) << "sendData"; mData.setOperationCode(mRequest.getOperationCode()); mData.setTransactionID(mRequest.getTransactionID()); int ret = mData.write(mRequestOut); mData.dump(); return (ret > 0); } bool MtpDevice::readData() { mData.reset(); int ret = mData.read(mRequestIn1); VLOG(2) << "readData returned " << ret; if (ret >= MTP_CONTAINER_HEADER_SIZE) { if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) { VLOG(2) << "got response packet instead of data packet"; // we got a response packet rather than data // copy it to mResponse mResponse.copyFrom(mData); mReceivedResponse = true; return false; } mData.dump(); return true; } else { VLOG(2) << "readResponse failed"; return false; } } bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { mData.setOperationCode(operation); mData.setTransactionID(mRequest.getTransactionID()); return (!mData.writeDataHeader(mRequestOut, dataLength)); } MtpResponseCode MtpDevice::readResponse() { VLOG(2) << "readResponse"; if (mReceivedResponse) { mReceivedResponse = false; return mResponse.getResponseCode(); } int ret = mResponse.read(mRequestIn1); // handle zero length packets, which might occur if the data transfer // ends on a packet boundary if (ret == 0) ret = mResponse.read(mRequestIn1); if (ret >= MTP_CONTAINER_HEADER_SIZE) { mResponse.dump(); return mResponse.getResponseCode(); } else { VLOG(2) << "readResponse failed"; return -1; } } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpStorage.cpp0000644000015301777760000000451012321133675020276 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpStorage" #include "MtpDebug.h" #include "MtpDatabase.h" #include "MtpStorage.h" #include #include #include #include #include #include #include #include #include #include namespace android { MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, const char* description, uint64_t reserveSpace, bool removable, uint64_t maxFileSize) : mStorageID(id), mFilePath(filePath), mDescription(description), mMaxCapacity(0), mMaxFileSize(maxFileSize), mReserveSpace(reserveSpace), mRemovable(removable) { VLOG(2) << "MtpStorage id: " << id << " path: " << filePath; } MtpStorage::~MtpStorage() { } int MtpStorage::getType() const { return (mRemovable ? MTP_STORAGE_REMOVABLE_RAM : MTP_STORAGE_FIXED_RAM); } int MtpStorage::getFileSystemType() const { return MTP_STORAGE_FILESYSTEM_HIERARCHICAL; } int MtpStorage::getAccessCapability() const { return MTP_STORAGE_READ_WRITE; } uint64_t MtpStorage::getMaxCapacity() { if (mMaxCapacity == 0) { struct statfs stat; if (statfs(getPath(), &stat)) return -1; mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize; } return mMaxCapacity; } uint64_t MtpStorage::getFreeSpace() { struct statfs stat; if (statfs(getPath(), &stat)) return -1; uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize; return (freeSpace > mReserveSpace ? freeSpace - mReserveSpace : 0); } const char* MtpStorage::getDescription() const { return mDescription.c_str(); } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpResponsePacket.cpp0000644000015301777760000000276312321133655021626 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpResponsePacket" #include #include #include #include #include "MtpResponsePacket.h" #include namespace android { MtpResponsePacket::MtpResponsePacket() : MtpPacket(512) { } MtpResponsePacket::~MtpResponsePacket() { } #ifdef MTP_DEVICE int MtpResponsePacket::write(int fd) { putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize); putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_RESPONSE); int ret = ::write(fd, mBuffer, mPacketSize); return (ret < 0 ? ret : 0); } #endif #ifdef MTP_HOST int MtpResponsePacket::read(struct usb_request *request) { request->buffer = mBuffer; request->buffer_length = mBufferSize; int ret = transfer(request); if (ret >= 0) mPacketSize = ret; else mPacketSize = 0; return ret; } #endif } // namespace android mtp-0.0.3+14.04.20140409/src/MtpDeviceInfo.cpp0000644000015301777760000000612112321133675020705 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpDeviceInfo" #include "MtpDebug.h" #include "MtpDataPacket.h" #include "MtpDeviceInfo.h" #include "MtpStringBuffer.h" #include #include namespace android { MtpDeviceInfo::MtpDeviceInfo() : mStandardVersion(0), mVendorExtensionID(0), mVendorExtensionVersion(0), mVendorExtensionDesc(NULL), mFunctionalCode(0), mOperations(NULL), mEvents(NULL), mDeviceProperties(NULL), mCaptureFormats(NULL), mPlaybackFormats(NULL), mManufacturer(NULL), mModel(NULL), mVersion(NULL), mSerial(NULL) { } MtpDeviceInfo::~MtpDeviceInfo() { if (mVendorExtensionDesc) free(mVendorExtensionDesc); delete mOperations; delete mEvents; delete mDeviceProperties; delete mCaptureFormats; delete mPlaybackFormats; if (mManufacturer) free(mManufacturer); if (mModel) free(mModel); if (mVersion) free(mVersion); if (mSerial) free(mSerial); } void MtpDeviceInfo::read(MtpDataPacket& packet) { MtpStringBuffer string; // read the device info mStandardVersion = packet.getUInt16(); mVendorExtensionID = packet.getUInt32(); mVendorExtensionVersion = packet.getUInt16(); packet.getString(string); mVendorExtensionDesc = strdup((const char *)string); mFunctionalCode = packet.getUInt16(); mOperations = packet.getAUInt16(); mEvents = packet.getAUInt16(); mDeviceProperties = packet.getAUInt16(); mCaptureFormats = packet.getAUInt16(); mPlaybackFormats = packet.getAUInt16(); packet.getString(string); mManufacturer = strdup((const char *)string); packet.getString(string); mModel = strdup((const char *)string); packet.getString(string); mVersion = strdup((const char *)string); packet.getString(string); mSerial = strdup((const char *)string); } void MtpDeviceInfo::print() { VLOG(2) << "Device Info:" << "\n\tmStandardVersion: " << mStandardVersion << "\n\tmVendorExtensionID: " << mVendorExtensionID << "\n\tmVendorExtensionVersion: " << mVendorExtensionVersion << "\n\tmVendorExtensionDesc: " << mVendorExtensionDesc << "\n\tmFunctionalCode: " << mFunctionalCode << "\n\tmManufacturer: " << mManufacturer << "\n\tmModel: " << mModel << "\n\tmVersion: " << mVersion << "\n\tmSerial: " << mSerial; } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpObjectInfo.cpp0000644000015301777760000000731112321133675020716 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpObjectInfo" #include "MtpDebug.h" #include "MtpDataPacket.h" #include "MtpObjectInfo.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" #include #include #include namespace android { MtpObjectInfo::MtpObjectInfo(MtpObjectHandle handle) : mHandle(handle), mStorageID(0), mFormat(0), mProtectionStatus(0), mCompressedSize(0), mThumbFormat(0), mThumbCompressedSize(0), mThumbPixWidth(0), mThumbPixHeight(0), mImagePixWidth(0), mImagePixHeight(0), mImagePixDepth(0), mParent(0), mAssociationType(0), mAssociationDesc(0), mSequenceNumber(0), mName(NULL), mDateCreated(0), mDateModified(0), mKeywords(NULL) { } MtpObjectInfo::~MtpObjectInfo() { if (mName) free(mName); if (mKeywords) free(mKeywords); } void MtpObjectInfo::read(MtpDataPacket& packet) { MtpStringBuffer string; time_t time; mStorageID = packet.getUInt32(); mFormat = packet.getUInt16(); mProtectionStatus = packet.getUInt16(); mCompressedSize = packet.getUInt32(); mThumbFormat = packet.getUInt16(); mThumbCompressedSize = packet.getUInt32(); mThumbPixWidth = packet.getUInt32(); mThumbPixHeight = packet.getUInt32(); mImagePixWidth = packet.getUInt32(); mImagePixHeight = packet.getUInt32(); mImagePixDepth = packet.getUInt32(); mParent = packet.getUInt32(); mAssociationType = packet.getUInt16(); mAssociationDesc = packet.getUInt32(); mSequenceNumber = packet.getUInt32(); packet.getString(string); mName = strdup((const char *)string); packet.getString(string); if (parseDateTime((const char*)string, time)) mDateCreated = time; packet.getString(string); if (parseDateTime((const char*)string, time)) mDateModified = time; packet.getString(string); mKeywords = strdup((const char *)string); } void MtpObjectInfo::print() { VLOG(2) << "MtpObject Info " << mHandle << ": " << mName; VLOG(2) << " mStorageID: " << std::hex << mStorageID << " mFormat: " << mFormat << std::dec << " mProtectionStatus: " << mProtectionStatus; VLOG(2) << " mCompressedSize: " << mCompressedSize << " mThumbFormat: " << std::hex << mThumbFormat << std::dec << " mThumbCompressedSize: " << mThumbCompressedSize; VLOG(2) << " mThumbPixWidth: " << mThumbPixWidth << " mThumbPixHeight: " << mThumbPixHeight; VLOG(2) << " mImagePixWidth: " << mImagePixWidth << " mImagePixHeight: " << mImagePixHeight << " mImagePixDepth: " << mImagePixDepth; VLOG(2) << " mParent: " << std::hex << mParent << " mAssociationType: " << mAssociationType << std::dec << " mAssociationDesc: " << mAssociationDesc; VLOG(2) << " mSequenceNumber: " << mSequenceNumber << " mDateCreated: " << mDateCreated << " mDateModified: " << mDateModified << " mKeywords: " << mKeywords; } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpStorageInfo.cpp0000644000015301777760000000463312321133675021120 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpStorageInfo" #include #include #include "MtpDebug.h" #include "MtpDataPacket.h" #include "MtpStorageInfo.h" #include "MtpStringBuffer.h" #include namespace android { MtpStorageInfo::MtpStorageInfo(MtpStorageID id) : mStorageID(id), mStorageType(0), mFileSystemType(0), mAccessCapability(0), mMaxCapacity(0), mFreeSpaceBytes(0), mFreeSpaceObjects(0), mStorageDescription(NULL), mVolumeIdentifier(NULL) { } MtpStorageInfo::~MtpStorageInfo() { if (mStorageDescription) free(mStorageDescription); if (mVolumeIdentifier) free(mVolumeIdentifier); } void MtpStorageInfo::read(MtpDataPacket& packet) { MtpStringBuffer string; // read the device info mStorageType = packet.getUInt16(); mFileSystemType = packet.getUInt16(); mAccessCapability = packet.getUInt16(); mMaxCapacity = packet.getUInt64(); mFreeSpaceBytes = packet.getUInt64(); mFreeSpaceObjects = packet.getUInt32(); packet.getString(string); mStorageDescription = strdup((const char *)string); packet.getString(string); mVolumeIdentifier = strdup((const char *)string); } void MtpStorageInfo::print() { VLOG(2) << "Storage Info " << std::hex << mStorageID << std::dec << ":" << "\n\tmStorageType: " << mStorageType << "\n\tmFileSystemType: " << mFileSystemType << "\n\tmAccessCapability: " << mAccessCapability; VLOG(2) << "\tmMaxCapacity: " << mMaxCapacity << "\n\tmFreeSpaceBytes: " << mFreeSpaceBytes << "\n\tmFreeSpaceObjects: " << mFreeSpaceObjects; VLOG(2) << "\tmStorageDescription: " << mStorageDescription << "\n\tmVolumeIdentifier: " << mVolumeIdentifier; } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpStringBuffer.cpp0000644000015301777760000001107412321133655021273 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "MtpStringBuffer" #include #include "MtpDataPacket.h" #include "MtpStringBuffer.h" namespace android { MtpStringBuffer::MtpStringBuffer() : mCharCount(0), mByteCount(1) { mBuffer[0] = 0; } MtpStringBuffer::MtpStringBuffer(const char* src) : mCharCount(0), mByteCount(1) { set(src); } MtpStringBuffer::MtpStringBuffer(const uint16_t* src) : mCharCount(0), mByteCount(1) { set(src); } MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src) : mCharCount(src.mCharCount), mByteCount(src.mByteCount) { memcpy(mBuffer, src.mBuffer, mByteCount); } MtpStringBuffer::~MtpStringBuffer() { } void MtpStringBuffer::set(const char* src) { int length = strlen(src); if (length >= sizeof(mBuffer)) length = sizeof(mBuffer) - 1; memcpy(mBuffer, src, length); // count the characters int count = 0; char ch; while ((ch = *src++) != 0) { if ((ch & 0x80) == 0) { // single byte character } else if ((ch & 0xE0) == 0xC0) { // two byte character if (! *src++) { // last character was truncated, so ignore last byte length--; break; } } else if ((ch & 0xF0) == 0xE0) { // 3 byte char if (! *src++) { // last character was truncated, so ignore last byte length--; break; } if (! *src++) { // last character was truncated, so ignore last two bytes length -= 2; break; } } count++; } mByteCount = length + 1; mBuffer[length] = 0; mCharCount = count; } void MtpStringBuffer::set(const uint16_t* src) { int count = 0; uint16_t ch; uint8_t* dest = mBuffer; while ((ch = *src++) != 0 && count < 255) { if (ch >= 0x0800) { *dest++ = (uint8_t)(0xE0 | (ch >> 12)); *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F)); *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); } else if (ch >= 0x80) { *dest++ = (uint8_t)(0xC0 | (ch >> 6)); *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); } else { *dest++ = ch; } count++; } *dest++ = 0; mCharCount = count; mByteCount = dest - mBuffer; } void MtpStringBuffer::readFromPacket(MtpDataPacket* packet) { int count = packet->getUInt8(); uint8_t* dest = mBuffer; for (int i = 0; i < count; i++) { uint16_t ch = packet->getUInt16(); if (ch >= 0x0800) { *dest++ = (uint8_t)(0xE0 | (ch >> 12)); *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F)); *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); } else if (ch >= 0x80) { *dest++ = (uint8_t)(0xC0 | (ch >> 6)); *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); } else { *dest++ = ch; } } *dest++ = 0; mCharCount = count; mByteCount = dest - mBuffer; } void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const { int count = mCharCount; const uint8_t* src = mBuffer; packet->putUInt8(count > 0 ? count + 1 : 0); // expand utf8 to 16 bit chars for (int i = 0; i < count; i++) { uint16_t ch; uint16_t ch1 = *src++; if ((ch1 & 0x80) == 0) { // single byte character ch = ch1; } else if ((ch1 & 0xE0) == 0xC0) { // two byte character uint16_t ch2 = *src++; ch = ((ch1 & 0x1F) << 6) | (ch2 & 0x3F); } else { // three byte character uint16_t ch2 = *src++; uint16_t ch3 = *src++; ch = ((ch1 & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F); } packet->putUInt16(ch); } // only terminate with zero if string is not empty if (count > 0) packet->putUInt16(0); } } // namespace android mtp-0.0.3+14.04.20140409/src/MtpServer.cpp0000644000015301777760000012222112321133675020140 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "MtpServer" #include "MtpDebug.h" #include "MtpDatabase.h" #include "MtpObjectInfo.h" #include "MtpProperty.h" #include "MtpServer.h" #include "MtpStorage.h" #include "MtpStringBuffer.h" #include #include #include namespace android { static const MtpOperationCode kSupportedOperationCodes[] = { MTP_OPERATION_GET_DEVICE_INFO, MTP_OPERATION_OPEN_SESSION, MTP_OPERATION_CLOSE_SESSION, MTP_OPERATION_GET_STORAGE_IDS, MTP_OPERATION_GET_STORAGE_INFO, MTP_OPERATION_GET_NUM_OBJECTS, MTP_OPERATION_GET_OBJECT_HANDLES, MTP_OPERATION_GET_OBJECT_INFO, MTP_OPERATION_GET_OBJECT, MTP_OPERATION_GET_THUMB, MTP_OPERATION_DELETE_OBJECT, MTP_OPERATION_SEND_OBJECT_INFO, MTP_OPERATION_SEND_OBJECT, // MTP_OPERATION_INITIATE_CAPTURE, // MTP_OPERATION_FORMAT_STORE, // MTP_OPERATION_RESET_DEVICE, // MTP_OPERATION_SELF_TEST, // MTP_OPERATION_SET_OBJECT_PROTECTION, // MTP_OPERATION_POWER_DOWN, MTP_OPERATION_GET_DEVICE_PROP_DESC, MTP_OPERATION_GET_DEVICE_PROP_VALUE, MTP_OPERATION_SET_DEVICE_PROP_VALUE, MTP_OPERATION_RESET_DEVICE_PROP_VALUE, // MTP_OPERATION_TERMINATE_OPEN_CAPTURE, MTP_OPERATION_MOVE_OBJECT, // MTP_OPERATION_COPY_OBJECT, MTP_OPERATION_GET_PARTIAL_OBJECT, // MTP_OPERATION_INITIATE_OPEN_CAPTURE, MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED, MTP_OPERATION_GET_OBJECT_PROP_DESC, MTP_OPERATION_GET_OBJECT_PROP_VALUE, MTP_OPERATION_SET_OBJECT_PROP_VALUE, MTP_OPERATION_GET_OBJECT_PROP_LIST, // MTP_OPERATION_SET_OBJECT_PROP_LIST, // MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC, // MTP_OPERATION_SEND_OBJECT_PROP_LIST, MTP_OPERATION_GET_OBJECT_REFERENCES, MTP_OPERATION_SET_OBJECT_REFERENCES, // MTP_OPERATION_SKIP, // Android extension for direct file IO MTP_OPERATION_GET_PARTIAL_OBJECT_64, MTP_OPERATION_SEND_PARTIAL_OBJECT, MTP_OPERATION_TRUNCATE_OBJECT, MTP_OPERATION_BEGIN_EDIT_OBJECT, MTP_OPERATION_END_EDIT_OBJECT, }; static const MtpEventCode kSupportedEventCodes[] = { MTP_EVENT_OBJECT_ADDED, MTP_EVENT_OBJECT_REMOVED, MTP_EVENT_STORE_ADDED, MTP_EVENT_STORE_REMOVED, MTP_EVENT_OBJECT_INFO_CHANGED, MTP_EVENT_OBJECT_PROP_CHANGED, }; MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm) : mFD(fd), mDatabase(database), mPtp(ptp), mFileGroup(fileGroup), mFilePermission(filePerm), mDirectoryPermission(directoryPerm), mSessionID(0), mSessionOpen(false), mSendObjectHandle(kInvalidObjectHandle), mSendObjectFormat(0), mSendObjectFileSize(0) { } MtpServer::~MtpServer() { } void MtpServer::addStorage(MtpStorage* storage) { MtpAutolock autoLock(mMutex); mStorages.push_back(storage); sendStoreAdded(storage->getStorageID()); } void MtpServer::removeStorage(MtpStorage* storage) { MtpAutolock autoLock(mMutex); for (int i = 0; i < mStorages.size(); i++) { if (mStorages[i] == storage) { mStorages.erase(mStorages.begin()+i); sendStoreRemoved(storage->getStorageID()); break; } } } MtpStorage* MtpServer::getStorage(MtpStorageID id) { if (id == 0) return mStorages[0]; for (int i = 0; i < mStorages.size(); i++) { MtpStorage* storage = mStorages[i]; if (storage->getStorageID() == id) return storage; } return NULL; } bool MtpServer::hasStorage(MtpStorageID id) { if (id == 0 || id == 0xFFFFFFFF) return mStorages.size() > 0; return (getStorage(id) != NULL); } void MtpServer::run() { int fd = mFD; VLOG(1) << "MtpServer::run fd: " << fd; while (1) { int ret = mRequest.read(fd); if (ret < 0) { PLOG(ERROR) << "request read returned " << ret; if (errno == ECANCELED) { // return to top of loop and wait for next command continue; } break; } MtpOperationCode operation = mRequest.getOperationCode(); MtpTransactionID transaction = mRequest.getTransactionID(); VLOG(2) << "operation: " << MtpDebug::getOperationCodeName(operation); mRequest.dump(); // FIXME need to generalize this bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO || operation == MTP_OPERATION_SET_OBJECT_REFERENCES || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE); if (dataIn) { int ret = mData.read(fd); if (ret < 0) { PLOG(ERROR) << "data read returned " << ret; if (errno == ECANCELED) { // return to top of loop and wait for next command continue; } break; } VLOG(2) << "received data:"; mData.dump(); } else { mData.reset(); } if (handleRequest()) { if (!dataIn && mData.hasData()) { mData.setOperationCode(operation); mData.setTransactionID(transaction); VLOG(2) << "sending data:"; mData.dump(); ret = mData.write(fd); if (ret < 0) { PLOG(ERROR) << "request write returned " << ret; if (errno == ECANCELED) { // return to top of loop and wait for next command continue; } break; } } mResponse.setTransactionID(transaction); VLOG(2) << "sending response " << std::hex << mResponse.getResponseCode() << std::dec; ret = mResponse.write(fd); mResponse.dump(); if (ret < 0) { PLOG(ERROR) << "request write returned " << ret; if (errno == ECANCELED) { // return to top of loop and wait for next command continue; } break; } } else { VLOG(2) << "skipping response"; } } // commit any open edits int count = mObjectEditList.size(); for (int i = 0; i < count; i++) { ObjectEdit* edit = mObjectEditList[i]; commitEdit(edit); delete edit; } mObjectEditList.clear(); if (mSessionOpen) mDatabase->sessionEnded(); close(fd); mFD = -1; } void MtpServer::sendObjectAdded(MtpObjectHandle handle) { VLOG(1) << "sendObjectAdded " << handle; sendEvent(MTP_EVENT_OBJECT_ADDED, handle, 0, 0); } void MtpServer::sendObjectRemoved(MtpObjectHandle handle) { VLOG(1) << "sendObjectRemoved " << handle; sendEvent(MTP_EVENT_OBJECT_REMOVED, handle, 0, 0); } void MtpServer::sendObjectInfoChanged(MtpObjectHandle handle) { VLOG(1) << "sendObjectInfoChanged " << handle; sendEvent(MTP_EVENT_OBJECT_INFO_CHANGED, handle, 0, 0); } void MtpServer::sendObjectPropChanged(MtpObjectHandle handle, MtpObjectProperty prop) { VLOG(1) << "sendObjectPropChanged " << handle << " " << prop; sendEvent(MTP_EVENT_OBJECT_PROP_CHANGED, handle, prop, 0); } void MtpServer::sendStoreAdded(MtpStorageID id) { VLOG(1) << "sendStoreAdded " << std::hex << id << std::dec; sendEvent(MTP_EVENT_STORE_ADDED, id, 0, 0); } void MtpServer::sendStoreRemoved(MtpStorageID id) { VLOG(1) << "sendStoreRemoved " << std::hex << id << std::dec; sendEvent(MTP_EVENT_STORE_REMOVED, id, 0, 0); } void MtpServer::sendEvent(MtpEventCode code, uint32_t param1, uint32_t param2, uint32_t param3) { if (mSessionOpen) { mEvent.setEventCode(code); mEvent.setTransactionID(mRequest.getTransactionID()); mEvent.setParameter(1, param1); mEvent.setParameter(2, param2); mEvent.setParameter(3, param3); int ret = mEvent.write(mFD); VLOG(2) << "mEvent.write returned " << ret; } } void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd) { ObjectEdit* edit = new ObjectEdit(handle, path, size, format, fd); mObjectEditList.push_back(edit); } MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) { int count = mObjectEditList.size(); for (int i = 0; i < count; i++) { ObjectEdit* edit = mObjectEditList[i]; if (edit->mHandle == handle) return edit; } return NULL; } void MtpServer::removeEditObject(MtpObjectHandle handle) { int count = mObjectEditList.size(); for (int i = 0; i < count; i++) { ObjectEdit* edit = mObjectEditList[i]; if (edit->mHandle == handle) { delete edit; mObjectEditList.erase(mObjectEditList.begin() + i); return; } } LOG(ERROR) << "ObjectEdit not found in removeEditObject"; } void MtpServer::commitEdit(ObjectEdit* edit) { mDatabase->endSendObject(edit->mPath.c_str(), edit->mHandle, edit->mFormat, true); } bool MtpServer::handleRequest() { MtpAutolock autoLock(mMutex); MtpOperationCode operation = mRequest.getOperationCode(); MtpResponseCode response; mResponse.reset(); if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) { // FIXME - need to delete mSendObjectHandle from the database LOG(ERROR) << "expected SendObject after SendObjectInfo"; mSendObjectHandle = kInvalidObjectHandle; } switch (operation) { case MTP_OPERATION_GET_DEVICE_INFO: response = doGetDeviceInfo(); break; case MTP_OPERATION_OPEN_SESSION: response = doOpenSession(); break; case MTP_OPERATION_CLOSE_SESSION: response = doCloseSession(); break; case MTP_OPERATION_GET_STORAGE_IDS: response = doGetStorageIDs(); break; case MTP_OPERATION_GET_STORAGE_INFO: response = doGetStorageInfo(); break; case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED: response = doGetObjectPropsSupported(); break; case MTP_OPERATION_GET_OBJECT_HANDLES: response = doGetObjectHandles(); break; case MTP_OPERATION_GET_NUM_OBJECTS: response = doGetNumObjects(); break; case MTP_OPERATION_GET_OBJECT_REFERENCES: response = doGetObjectReferences(); break; case MTP_OPERATION_SET_OBJECT_REFERENCES: response = doSetObjectReferences(); break; case MTP_OPERATION_GET_OBJECT_PROP_VALUE: response = doGetObjectPropValue(); break; case MTP_OPERATION_SET_OBJECT_PROP_VALUE: response = doSetObjectPropValue(); break; case MTP_OPERATION_GET_DEVICE_PROP_VALUE: response = doGetDevicePropValue(); break; case MTP_OPERATION_SET_DEVICE_PROP_VALUE: response = doSetDevicePropValue(); break; case MTP_OPERATION_RESET_DEVICE_PROP_VALUE: response = doResetDevicePropValue(); break; case MTP_OPERATION_GET_OBJECT_PROP_LIST: response = doGetObjectPropList(); break; case MTP_OPERATION_GET_OBJECT_INFO: response = doGetObjectInfo(); break; case MTP_OPERATION_GET_OBJECT: response = doGetObject(); break; case MTP_OPERATION_GET_THUMB: response = doGetThumb(); break; case MTP_OPERATION_GET_PARTIAL_OBJECT: case MTP_OPERATION_GET_PARTIAL_OBJECT_64: response = doGetPartialObject(operation); break; case MTP_OPERATION_SEND_OBJECT_INFO: response = doSendObjectInfo(); break; case MTP_OPERATION_SEND_OBJECT: response = doSendObject(); break; case MTP_OPERATION_DELETE_OBJECT: response = doDeleteObject(); break; case MTP_OPERATION_MOVE_OBJECT: response = doMoveObject(); break; case MTP_OPERATION_GET_OBJECT_PROP_DESC: response = doGetObjectPropDesc(); break; case MTP_OPERATION_GET_DEVICE_PROP_DESC: response = doGetDevicePropDesc(); break; case MTP_OPERATION_SEND_PARTIAL_OBJECT: response = doSendPartialObject(); break; case MTP_OPERATION_TRUNCATE_OBJECT: response = doTruncateObject(); break; case MTP_OPERATION_BEGIN_EDIT_OBJECT: response = doBeginEditObject(); break; case MTP_OPERATION_END_EDIT_OBJECT: response = doEndEditObject(); break; default: LOG(ERROR) << "got unsupported command " << MtpDebug::getOperationCodeName(operation); response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; } if (response == MTP_RESPONSE_TRANSACTION_CANCELLED) return false; mResponse.setResponseCode(response); return true; } MtpResponseCode MtpServer::doGetDeviceInfo() { VLOG(1) << __PRETTY_FUNCTION__; MtpStringBuffer string; char prop_value[PROP_VALUE_MAX]; MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats(); MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats(); MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties(); // fill in device info mData.putUInt16(MTP_STANDARD_VERSION); if (mPtp) { mData.putUInt32(0); } else { // MTP Vendor Extension ID mData.putUInt32(6); } mData.putUInt16(MTP_STANDARD_VERSION); if (mPtp) { // no extensions string.set(""); } else { // MTP extensions string.set("microsoft.com: 1.0; android.com: 1.0;"); } mData.putString(string); // MTP Extensions mData.putUInt16(0); //Functional Mode mData.putAUInt16(kSupportedOperationCodes, sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported mData.putAUInt16(kSupportedEventCodes, sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported mData.putAUInt16(deviceProperties); // Device Properties Supported mData.putAUInt16(captureFormats); // Capture Formats mData.putAUInt16(playbackFormats); // Playback Formats property_get("ro.product.manufacturer", prop_value, "unknown manufacturer"); string.set(prop_value); mData.putString(string); // Manufacturer property_get("ro.product.model", prop_value, "MTP Device"); string.set(prop_value); mData.putString(string); // Model string.set("1.0"); mData.putString(string); // Device Version property_get("ro.serialno", prop_value, "????????"); string.set(prop_value); mData.putString(string); // Serial Number delete playbackFormats; delete captureFormats; delete deviceProperties; return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doOpenSession() { if (mSessionOpen) { mResponse.setParameter(1, mSessionID); return MTP_RESPONSE_SESSION_ALREADY_OPEN; } mSessionID = mRequest.getParameter(1); mSessionOpen = true; mDatabase->sessionStarted(this); return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doCloseSession() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; mSessionID = 0; mSessionOpen = false; mDatabase->sessionEnded(); return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetStorageIDs() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; int count = mStorages.size(); mData.putUInt32(count); for (int i = 0; i < count; i++) mData.putUInt32(mStorages[i]->getStorageID()); return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetStorageInfo() { MtpStringBuffer string; if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; MtpStorageID id = mRequest.getParameter(1); MtpStorage* storage = getStorage(id); if (!storage) return MTP_RESPONSE_INVALID_STORAGE_ID; mData.putUInt16(storage->getType()); mData.putUInt16(storage->getFileSystemType()); mData.putUInt16(storage->getAccessCapability()); mData.putUInt64(storage->getMaxCapacity()); mData.putUInt64(storage->getFreeSpace()); mData.putUInt32(1024*1024*1024); // Free Space in Objects string.set(storage->getDescription()); mData.putString(string); mData.putEmptyString(); // Volume Identifier return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetObjectPropsSupported() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; MtpObjectFormat format = mRequest.getParameter(1); MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format); mData.putAUInt16(properties); delete properties; return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetObjectHandles() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent // 0x00000000 for all objects if (!hasStorage(storageID)) return MTP_RESPONSE_INVALID_STORAGE_ID; MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent); mData.putAUInt32(handles); delete handles; return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetNumObjects() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; MtpStorageID storageID = mRequest.getParameter(1); // 0xFFFFFFFF for all storage MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent // 0x00000000 for all objects if (!hasStorage(storageID)) return MTP_RESPONSE_INVALID_STORAGE_ID; int count = mDatabase->getNumObjects(storageID, format, parent); if (count >= 0) { mResponse.setParameter(1, count); return MTP_RESPONSE_OK; } else { mResponse.setParameter(1, 0); return MTP_RESPONSE_INVALID_OBJECT_HANDLE; } } MtpResponseCode MtpServer::doGetObjectReferences() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); // FIXME - check for invalid object handle MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle); if (handles) { mData.putAUInt32(handles); delete handles; } else { mData.putEmptyArray(); } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doSetObjectReferences() { if (!mSessionOpen) return MTP_RESPONSE_SESSION_NOT_OPEN; if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpStorageID handle = mRequest.getParameter(1); MtpObjectHandleList* references = mData.getAUInt32(); MtpResponseCode result = mDatabase->setObjectReferences(handle, references); delete references; return result; } MtpResponseCode MtpServer::doGetObjectPropValue() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectProperty property = mRequest.getParameter(2); VLOG(2) << "GetObjectPropValue " << handle << " " << MtpDebug::getObjectPropCodeName(property); return mDatabase->getObjectPropertyValue(handle, property, mData); } MtpResponseCode MtpServer::doSetObjectPropValue() { MtpResponseCode response; if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectProperty property = mRequest.getParameter(2); VLOG(2) << "SetObjectPropValue " << handle << " " << MtpDebug::getObjectPropCodeName(property); response = mDatabase->setObjectPropertyValue(handle, property, mData); //sendObjectPropChanged(handle, property); return response; } MtpResponseCode MtpServer::doGetDevicePropValue() { MtpDeviceProperty property = mRequest.getParameter(1); VLOG(1) << "GetDevicePropValue " << MtpDebug::getDevicePropCodeName(property); return mDatabase->getDevicePropertyValue(property, mData); } MtpResponseCode MtpServer::doSetDevicePropValue() { MtpDeviceProperty property = mRequest.getParameter(1); VLOG(1) << "SetDevicePropValue " << MtpDebug::getDevicePropCodeName(property); return mDatabase->setDevicePropertyValue(property, mData); } MtpResponseCode MtpServer::doResetDevicePropValue() { MtpDeviceProperty property = mRequest.getParameter(1); VLOG(1) << "ResetDevicePropValue " << MtpDebug::getDevicePropCodeName(property); return mDatabase->resetDeviceProperty(property); } MtpResponseCode MtpServer::doGetObjectPropList() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); // use uint32_t so we can support 0xFFFFFFFF uint32_t format = mRequest.getParameter(2); uint32_t property = mRequest.getParameter(3); int groupCode = mRequest.getParameter(4); int depth = mRequest.getParameter(5); VLOG(2) << "GetObjectPropList " << handle << " format: " << MtpDebug::getFormatCodeName(format) << " property: " << MtpDebug::getObjectPropCodeName(property) << " group: " << groupCode << " depth: " << depth; return mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData); } MtpResponseCode MtpServer::doGetObjectInfo() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectInfo info(handle); MtpResponseCode result = mDatabase->getObjectInfo(handle, info); if (result == MTP_RESPONSE_OK) { char date[20]; mData.putUInt32(info.mStorageID); mData.putUInt16(info.mFormat); mData.putUInt16(info.mProtectionStatus); // if object is being edited the database size may be out of date uint32_t size = info.mCompressedSize; ObjectEdit* edit = getEditObject(handle); if (edit) size = (edit->mSize > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)edit->mSize); mData.putUInt32(size); mData.putUInt16(info.mThumbFormat); mData.putUInt32(info.mThumbCompressedSize); mData.putUInt32(info.mThumbPixWidth); mData.putUInt32(info.mThumbPixHeight); mData.putUInt32(info.mImagePixWidth); mData.putUInt32(info.mImagePixHeight); mData.putUInt32(info.mImagePixDepth); mData.putUInt32(info.mParent); mData.putUInt16(info.mAssociationType); mData.putUInt32(info.mAssociationDesc); mData.putUInt32(info.mSequenceNumber); mData.putString(info.mName); mData.putEmptyString(); // date created formatDateTime(info.mDateModified, date, sizeof(date)); mData.putString(date); // date modified mData.putEmptyString(); // keywords } return result; } MtpResponseCode MtpServer::doGetObject() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpString pathBuf; int64_t fileLength; MtpObjectFormat format; int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format); if (result != MTP_RESPONSE_OK) return result; mtp_file_range mfr; mfr.fd = open(pathBuf.c_str(), O_RDONLY); if (mfr.fd < 0) { return MTP_RESPONSE_GENERAL_ERROR; } mfr.offset = 0; mfr.length = fileLength; mfr.command = mRequest.getOperationCode(); mfr.transaction_id = mRequest.getTransactionID(); // then transfer the file int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr); VLOG(2) << "MTP_SEND_FILE_WITH_HEADER returned " << ret; close(mfr.fd); if (ret < 0) { if (errno == ECANCELED) return MTP_RESPONSE_TRANSACTION_CANCELLED; else return MTP_RESPONSE_GENERAL_ERROR; } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetThumb() { MtpObjectHandle handle = mRequest.getParameter(1); size_t thumbSize; void* thumb = mDatabase->getThumbnail(handle, thumbSize); if (thumb) { // send data mData.setOperationCode(mRequest.getOperationCode()); mData.setTransactionID(mRequest.getTransactionID()); mData.writeData(mFD, thumb, thumbSize); free(thumb); return MTP_RESPONSE_OK; } else { return MTP_RESPONSE_GENERAL_ERROR; } } MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); uint64_t offset; uint32_t length; offset = mRequest.getParameter(2); if (operation == MTP_OPERATION_GET_PARTIAL_OBJECT_64) { // android extension with 64 bit offset uint64_t offset2 = mRequest.getParameter(3); offset = offset | (offset2 << 32); length = mRequest.getParameter(4); } else { // standard GetPartialObject length = mRequest.getParameter(3); } MtpString pathBuf; int64_t fileLength; MtpObjectFormat format; int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format); if (result != MTP_RESPONSE_OK) return result; if (offset + length > fileLength) length = fileLength - offset; mtp_file_range mfr; mfr.fd = open(pathBuf.c_str(), O_RDONLY); if (mfr.fd < 0) { return MTP_RESPONSE_GENERAL_ERROR; } mfr.offset = offset; mfr.length = length; mfr.command = mRequest.getOperationCode(); mfr.transaction_id = mRequest.getTransactionID(); mResponse.setParameter(1, length); // transfer the file int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr); VLOG(2) << "MTP_SEND_FILE_WITH_HEADER returned " << ret; close(mfr.fd); if (ret < 0) { if (errno == ECANCELED) return MTP_RESPONSE_TRANSACTION_CANCELLED; else return MTP_RESPONSE_GENERAL_ERROR; } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doSendObjectInfo() { MtpString path; MtpStorageID storageID = mRequest.getParameter(1); MtpStorage* storage = getStorage(storageID); MtpObjectHandle parent = mRequest.getParameter(2); if (!storage) return MTP_RESPONSE_INVALID_STORAGE_ID; // special case the root if (parent == MTP_PARENT_ROOT) { path = storage->getPath(); parent = 0; } else { int64_t length; MtpObjectFormat format; int result = mDatabase->getObjectFilePath(parent, path, length, format); if (result != MTP_RESPONSE_OK) return result; if (format != MTP_FORMAT_ASSOCIATION) return MTP_RESPONSE_INVALID_PARENT_OBJECT; } // read only the fields we need mData.getUInt32(); // storage ID MtpObjectFormat format = mData.getUInt16(); mData.getUInt16(); // protection status mSendObjectFileSize = mData.getUInt32(); mData.getUInt16(); // thumb format mData.getUInt32(); // thumb compressed size mData.getUInt32(); // thumb pix width mData.getUInt32(); // thumb pix height mData.getUInt32(); // image pix width mData.getUInt32(); // image pix height mData.getUInt32(); // image bit depth mData.getUInt32(); // parent uint16_t associationType = mData.getUInt16(); uint32_t associationDesc = mData.getUInt32(); // association desc mData.getUInt32(); // sequence number MtpStringBuffer name, created, modified; mData.getString(name); // file name mData.getString(created); // date created mData.getString(modified); // date modified // keywords follow VLOG(2) << "name: " << (const char *) name << " format: " << std::hex << format << std::dec; time_t modifiedTime; if (!parseDateTime(modified, modifiedTime)) modifiedTime = 0; if (path[path.size() - 1] != '/') path += "/"; path += (const char *)name; // check space first if (mSendObjectFileSize > storage->getFreeSpace()) return MTP_RESPONSE_STORAGE_FULL; uint64_t maxFileSize = storage->getMaxFileSize(); // check storage max file size if (maxFileSize != 0) { // if mSendObjectFileSize is 0xFFFFFFFF, then all we know is the file size // is >= 0xFFFFFFFF if (mSendObjectFileSize > maxFileSize || mSendObjectFileSize == 0xFFFFFFFF) return MTP_RESPONSE_OBJECT_TOO_LARGE; } VLOG(2) << "path: " << path.c_str() << " parent: " << parent << " storageID: " << std::hex << storageID << std::dec; MtpObjectHandle handle = mDatabase->beginSendObject(path.c_str(), format, parent, storageID, mSendObjectFileSize, modifiedTime); if (handle == kInvalidObjectHandle) { return MTP_RESPONSE_GENERAL_ERROR; } if (format == MTP_FORMAT_ASSOCIATION) { mode_t mask = umask(0); int ret = mkdir(path.c_str(), mDirectoryPermission); umask(mask); if (ret && ret != -EEXIST) return MTP_RESPONSE_GENERAL_ERROR; chown(path.c_str(), getuid(), mFileGroup); // SendObject does not get sent for directories, so call endSendObject here instead mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK); } else { mSendObjectFilePath = path; // save the handle for the SendObject call, which should follow mSendObjectHandle = handle; mSendObjectFormat = format; } mResponse.setParameter(1, storageID); mResponse.setParameter(2, parent); mResponse.setParameter(3, handle); return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doSendObject() { if (!hasStorage()) return MTP_RESPONSE_GENERAL_ERROR; MtpResponseCode result = MTP_RESPONSE_OK; mode_t mask; int ret, initialData; if (mSendObjectHandle == kInvalidObjectHandle) { LOG(ERROR) << "Expected SendObjectInfo before SendObject"; result = MTP_RESPONSE_NO_VALID_OBJECT_INFO; goto done; } // read the header, and possibly some data ret = mData.read(mFD); if (ret < MTP_CONTAINER_HEADER_SIZE) { result = MTP_RESPONSE_GENERAL_ERROR; goto done; } initialData = ret - MTP_CONTAINER_HEADER_SIZE; mtp_file_range mfr; mfr.fd = open(mSendObjectFilePath.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (mfr.fd < 0) { result = MTP_RESPONSE_GENERAL_ERROR; goto done; } fchown(mfr.fd, getuid(), mFileGroup); // set permissions mask = umask(0); fchmod(mfr.fd, mFilePermission); umask(mask); if (initialData > 0) ret = write(mfr.fd, mData.getData(), initialData); if (mSendObjectFileSize - initialData > 0) { mfr.offset = initialData; if (mSendObjectFileSize == 0xFFFFFFFF) { // tell driver to read until it receives a short packet mfr.length = 0xFFFFFFFF; } else { mfr.length = mSendObjectFileSize - initialData; } VLOG(2) << "receiving " << mSendObjectFilePath.c_str(); // transfer the file ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); VLOG(2) << "MTP_RECEIVE_FILE returned " << ret; } close(mfr.fd); if (ret < 0) { unlink(mSendObjectFilePath.c_str()); if (errno == ECANCELED) result = MTP_RESPONSE_TRANSACTION_CANCELLED; else result = MTP_RESPONSE_GENERAL_ERROR; } done: // reset so we don't attempt to send the data back mData.reset(); mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat, result == MTP_RESPONSE_OK); mSendObjectHandle = kInvalidObjectHandle; mSendObjectFormat = 0; return result; } static void deleteRecursive(const char* path) { char pathbuf[PATH_MAX]; int pathLength = strlen(path); if (pathLength >= sizeof(pathbuf) - 1) { LOG(ERROR) << "path too long: " << path; } strcpy(pathbuf, path); if (pathbuf[pathLength - 1] != '/') { pathbuf[pathLength++] = '/'; } char* fileSpot = pathbuf + pathLength; int pathRemaining = sizeof(pathbuf) - pathLength - 1; DIR* dir = opendir(path); if (!dir) { PLOG(ERROR) << "opendir " << path << " failed"; return; } struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; // ignore "." and ".." if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { continue; } int nameLength = strlen(name); if (nameLength > pathRemaining) { LOG(ERROR) << "path " << path << "/" << name << " too long"; continue; } strcpy(fileSpot, name); int type = entry->d_type; if (entry->d_type == DT_DIR) { deleteRecursive(pathbuf); rmdir(pathbuf); } else { unlink(pathbuf); } } closedir(dir); } static void deletePath(const char* path) { struct stat statbuf; if (stat(path, &statbuf) == 0) { if (S_ISDIR(statbuf.st_mode)) { deleteRecursive(path); rmdir(path); } else { unlink(path); } } else { PLOG(ERROR) << "deletePath stat failed for " << path; } } MtpResponseCode MtpServer::doDeleteObject() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectFormat format = mRequest.getParameter(2); // FIXME - support deleting all objects if handle is 0xFFFFFFFF // FIXME - implement deleting objects by format MtpString filePath; int64_t fileLength; int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format); if (result == MTP_RESPONSE_OK) { VLOG(2) << "deleting " << filePath.c_str(); result = mDatabase->deleteFile(handle); // Don't delete the actual files unless the database deletion is allowed if (result == MTP_RESPONSE_OK) { deletePath(filePath.c_str()); } } return result; } MtpResponseCode MtpServer::doMoveObject() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectFormat format = mRequest.getParameter(2); MtpObjectHandle newparent = mRequest.getParameter(3); MtpString filePath; MtpString newPath; int64_t fileLength; int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format); result = mDatabase->getObjectFilePath(handle, newPath, fileLength, format); if (result == MTP_RESPONSE_OK) { VLOG(2) << "moving " << filePath.c_str() << " to " << newPath.c_str(); result = mDatabase->moveFile(handle, newparent); // Don't move the actual files unless the database deletion is allowed if (result == MTP_RESPONSE_OK) { rename(filePath.c_str(), newPath.c_str()); } } return result; } MtpResponseCode MtpServer::doGetObjectPropDesc() { MtpObjectProperty propCode = mRequest.getParameter(1); MtpObjectFormat format = mRequest.getParameter(2); VLOG(2) << "GetObjectPropDesc " << MtpDebug::getObjectPropCodeName(propCode) << " " << MtpDebug::getFormatCodeName(format); MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format); if (!property) return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; property->write(mData); delete property; return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doGetDevicePropDesc() { MtpDeviceProperty propCode = mRequest.getParameter(1); VLOG(1) << "GetDevicePropDesc " << MtpDebug::getDevicePropCodeName(propCode); MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode); if (!property) return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; property->write(mData); delete property; return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doSendPartialObject() { if (!hasStorage()) return MTP_RESPONSE_INVALID_OBJECT_HANDLE; MtpObjectHandle handle = mRequest.getParameter(1); uint64_t offset = mRequest.getParameter(2); uint64_t offset2 = mRequest.getParameter(3); offset = offset | (offset2 << 32); uint32_t length = mRequest.getParameter(4); ObjectEdit* edit = getEditObject(handle); if (!edit) { LOG(ERROR) << "object not open for edit in doSendPartialObject"; return MTP_RESPONSE_GENERAL_ERROR; } // can't start writing past the end of the file if (offset > edit->mSize) { VLOG(2) << "writing past end of object, offset: " << offset << " edit->mSize: " << edit->mSize; return MTP_RESPONSE_GENERAL_ERROR; } const char* filePath = edit->mPath.c_str(); VLOG(2) << "receiving partial " << filePath << " " << offset << " " << length; // read the header, and possibly some data int ret = mData.read(mFD); if (ret < MTP_CONTAINER_HEADER_SIZE) return MTP_RESPONSE_GENERAL_ERROR; int initialData = ret - MTP_CONTAINER_HEADER_SIZE; if (initialData > 0) { ret = write(edit->mFD, mData.getData(), initialData); offset += initialData; length -= initialData; } if (length > 0) { mtp_file_range mfr; mfr.fd = edit->mFD; mfr.offset = offset; mfr.length = length; // transfer the file ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr); VLOG(2) << "MTP_RECEIVE_FILE returned " << ret; } if (ret < 0) { mResponse.setParameter(1, 0); if (errno == ECANCELED) return MTP_RESPONSE_TRANSACTION_CANCELLED; else return MTP_RESPONSE_GENERAL_ERROR; } // reset so we don't attempt to send this back mData.reset(); mResponse.setParameter(1, length); uint64_t end = offset + length; if (end > edit->mSize) { edit->mSize = end; } return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doTruncateObject() { MtpObjectHandle handle = mRequest.getParameter(1); ObjectEdit* edit = getEditObject(handle); if (!edit) { LOG(ERROR) << "object not open for edit in doTruncateObject"; return MTP_RESPONSE_GENERAL_ERROR; } uint64_t offset = mRequest.getParameter(2); uint64_t offset2 = mRequest.getParameter(3); offset |= (offset2 << 32); if (ftruncate(edit->mFD, offset) != 0) { return MTP_RESPONSE_GENERAL_ERROR; } else { edit->mSize = offset; return MTP_RESPONSE_OK; } } MtpResponseCode MtpServer::doBeginEditObject() { MtpObjectHandle handle = mRequest.getParameter(1); if (getEditObject(handle)) { LOG(ERROR) << "object already open for edit in doBeginEditObject"; return MTP_RESPONSE_GENERAL_ERROR; } MtpString path; int64_t fileLength; MtpObjectFormat format; int result = mDatabase->getObjectFilePath(handle, path, fileLength, format); if (result != MTP_RESPONSE_OK) return result; int fd = open(path.c_str(), O_RDWR | O_EXCL); if (fd < 0) { PLOG(ERROR) << "open failed for " << path.c_str() << " in doBeginEditObject"; return MTP_RESPONSE_GENERAL_ERROR; } addEditObject(handle, path, fileLength, format, fd); return MTP_RESPONSE_OK; } MtpResponseCode MtpServer::doEndEditObject() { MtpObjectHandle handle = mRequest.getParameter(1); ObjectEdit* edit = getEditObject(handle); if (!edit) { LOG(ERROR) << "object not open for edit in doEndEditObject"; return MTP_RESPONSE_GENERAL_ERROR; } commitEdit(edit); removeEditObject(handle); return MTP_RESPONSE_OK; } } // namespace android mtp-0.0.3+14.04.20140409/NOTICE0000644000015301777760000002470712321133655015632 0ustar pbusernogroup00000000000000 Copyright (c) 2005-2008, The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS mtp-0.0.3+14.04.20140409/include/0000755000015301777760000000000012321134053016330 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/include/MtpDebug.h0000644000015301777760000000203512321133655020217 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_DEBUG_H #define _MTP_DEBUG_H #include "MtpTypes.h" namespace android { class MtpDebug { public: static const char* getOperationCodeName(MtpOperationCode code); static const char* getFormatCodeName(MtpObjectFormat code); static const char* getObjectPropCodeName(MtpPropertyCode code); static const char* getDevicePropCodeName(MtpPropertyCode code); }; }; // namespace android #endif // _MTP_DEBUG_H mtp-0.0.3+14.04.20140409/include/MtpStorage.h0000644000015301777760000000400312321133655020572 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_STORAGE_H #define _MTP_STORAGE_H #include "MtpTypes.h" #include "mtp.h" namespace android { class MtpDatabase; class MtpStorage { private: MtpStorageID mStorageID; MtpString mFilePath; MtpString mDescription; uint64_t mMaxCapacity; uint64_t mMaxFileSize; // amount of free space to leave unallocated uint64_t mReserveSpace; bool mRemovable; public: MtpStorage(MtpStorageID id, const char* filePath, const char* description, uint64_t reserveSpace, bool removable, uint64_t maxFileSize); virtual ~MtpStorage(); inline MtpStorageID getStorageID() const { return mStorageID; } int getType() const; int getFileSystemType() const; int getAccessCapability() const; uint64_t getMaxCapacity(); uint64_t getFreeSpace(); const char* getDescription() const; inline const char* getPath() const { return mFilePath.c_str(); } inline bool isRemovable() const { return mRemovable; } inline uint64_t getMaxFileSize() const { return mMaxFileSize; } }; }; // namespace android #endif // _MTP_STORAGE_H mtp-0.0.3+14.04.20140409/include/MtpUtils.h0000644000015301777760000000156612321133655020301 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_UTILS_H #define _MTP_UTILS_H #include namespace android { bool parseDateTime(const char* dateTime, time_t& outSeconds); void formatDateTime(time_t seconds, char* buffer, int bufferLength); }; // namespace android #endif // _MTP_UTILS_H mtp-0.0.3+14.04.20140409/include/MtpStringBuffer.h0000644000015301777760000000340712321133655021575 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_STRING_BUFFER_H #define _MTP_STRING_BUFFER_H #include namespace android { class MtpDataPacket; // Represents a utf8 string, with a maximum of 255 characters class MtpStringBuffer { private: // mBuffer contains string in UTF8 format // maximum 3 bytes/character, with 1 extra for zero termination uint8_t mBuffer[255 * 3 + 1]; int mCharCount; int mByteCount; public: MtpStringBuffer(); MtpStringBuffer(const char* src); MtpStringBuffer(const uint16_t* src); MtpStringBuffer(const MtpStringBuffer& src); virtual ~MtpStringBuffer(); void set(const char* src); void set(const uint16_t* src); void readFromPacket(MtpDataPacket* packet); void writeToPacket(MtpDataPacket* packet) const; inline int getCharCount() const { return mCharCount; } inline int getByteCount() const { return mByteCount; } inline operator const char*() const { return (const char *)mBuffer; } }; }; // namespace android #endif // _MTP_STRING_BUFFER_H mtp-0.0.3+14.04.20140409/include/MtpEventPacket.h0000644000015301777760000000260112321133655021401 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_EVENT_PACKET_H #define _MTP_EVENT_PACKET_H #include "MtpPacket.h" #include "mtp.h" namespace android { class MtpEventPacket : public MtpPacket { public: MtpEventPacket(); virtual ~MtpEventPacket(); #ifdef MTP_DEVICE // write our data to the given file descriptor int write(int fd); #endif #ifdef MTP_HOST // read our buffer with the given request int read(struct usb_request *request); #endif inline MtpEventCode getEventCode() const { return getContainerCode(); } inline void setEventCode(MtpEventCode code) { return setContainerCode(code); } }; }; // namespace android #endif // _MTP_EVENT_PACKET_H mtp-0.0.3+14.04.20140409/include/MtpPacket.h0000644000015301777760000000416412321133655020405 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_PACKET_H #define _MTP_PACKET_H #include "MtpTypes.h" struct usb_request; namespace android { class MtpPacket { protected: uint8_t* mBuffer; // current size of the buffer int mBufferSize; // number of bytes to add when resizing the buffer int mAllocationIncrement; // size of the data in the packet int mPacketSize; public: MtpPacket(int bufferSize); virtual ~MtpPacket(); // sets packet size to the default container size and sets buffer to zero virtual void reset(); void allocate(int length); void dump(); void copyFrom(const MtpPacket& src); uint16_t getContainerCode() const; void setContainerCode(uint16_t code); uint16_t getContainerType() const; MtpTransactionID getTransactionID() const; void setTransactionID(MtpTransactionID id); uint32_t getParameter(int index) const; void setParameter(int index, uint32_t value); #ifdef MTP_HOST int transfer(struct usb_request* request); #endif protected: uint16_t getUInt16(int offset) const; uint32_t getUInt32(int offset) const; void putUInt16(int offset, uint16_t value); void putUInt32(int offset, uint32_t value); }; }; // namespace android #endif // _MTP_PACKET_H mtp-0.0.3+14.04.20140409/include/MtpResponsePacket.h0000644000015301777760000000264412321133655022125 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_RESPONSE_PACKET_H #define _MTP_RESPONSE_PACKET_H #include "MtpPacket.h" #include "mtp.h" namespace android { class MtpResponsePacket : public MtpPacket { public: MtpResponsePacket(); virtual ~MtpResponsePacket(); #ifdef MTP_DEVICE // write our data to the given file descriptor int write(int fd); #endif #ifdef MTP_HOST // read our buffer with the given request int read(struct usb_request *request); #endif inline MtpResponseCode getResponseCode() const { return getContainerCode(); } inline void setResponseCode(MtpResponseCode code) { return setContainerCode(code); } }; }; // namespace android #endif // _MTP_RESPONSE_PACKET_H mtp-0.0.3+14.04.20140409/include/MtpStorageInfo.h0000644000015301777760000000256712321133655021423 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_STORAGE_INFO_H #define _MTP_STORAGE_INFO_H #include "MtpTypes.h" namespace android { class MtpDataPacket; class MtpStorageInfo { public: MtpStorageID mStorageID; uint16_t mStorageType; uint16_t mFileSystemType; uint16_t mAccessCapability; uint64_t mMaxCapacity; uint64_t mFreeSpaceBytes; uint32_t mFreeSpaceObjects; char* mStorageDescription; char* mVolumeIdentifier; public: MtpStorageInfo(MtpStorageID id); virtual ~MtpStorageInfo(); void read(MtpDataPacket& packet); void print(); }; }; // namespace android #endif // _MTP_STORAGE_INFO_H mtp-0.0.3+14.04.20140409/include/MtpProperty.h0000644000015301777760000000674412321133655021030 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_PROPERTY_H #define _MTP_PROPERTY_H #include "MtpTypes.h" namespace android { class MtpDataPacket; struct MtpPropertyValue { union { int8_t i8; uint8_t u8; int16_t i16; uint16_t u16; int32_t i32; uint32_t u32; int64_t i64; uint64_t u64; int128_t i128; uint128_t u128; } u; // string in UTF8 format char* str; }; class MtpProperty { public: MtpPropertyCode mCode; MtpDataType mType; bool mWriteable; MtpPropertyValue mDefaultValue; MtpPropertyValue mCurrentValue; // for array types int mDefaultArrayLength; MtpPropertyValue* mDefaultArrayValues; int mCurrentArrayLength; MtpPropertyValue* mCurrentArrayValues; enum { kFormNone = 0, kFormRange = 1, kFormEnum = 2, kFormDateTime = 3, }; uint32_t mGroupCode; uint8_t mFormFlag; // for range form MtpPropertyValue mMinimumValue; MtpPropertyValue mMaximumValue; MtpPropertyValue mStepSize; // for enum form int mEnumLength; MtpPropertyValue* mEnumValues; public: MtpProperty(); MtpProperty(MtpPropertyCode propCode, MtpDataType type, bool writeable = false, int defaultValue = 0); virtual ~MtpProperty(); inline MtpPropertyCode getPropertyCode() const { return mCode; } void read(MtpDataPacket& packet); void write(MtpDataPacket& packet); void setDefaultValue(const uint16_t* string); void setCurrentValue(const uint16_t* string); void setFormRange(int min, int max, int step); void setFormEnum(const int* values, int count); void setFormDateTime(); void print(); void print(MtpPropertyValue& value, MtpString& buffer); inline bool isDeviceProperty() const { return ( ((mCode & 0xF000) == 0x5000) || ((mCode & 0xF800) == 0xD000)); } private: void readValue(MtpDataPacket& packet, MtpPropertyValue& value); void writeValue(MtpDataPacket& packet, MtpPropertyValue& value); MtpPropertyValue* readArrayValues(MtpDataPacket& packet, int& length); void writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length); }; }; // namespace android #endif // _MTP_PROPERTY_H mtp-0.0.3+14.04.20140409/include/mtp.h0000644000015301777760000007507012321133655017321 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_H #define _MTP_H #include #include #define MTP_STANDARD_VERSION 100 // Container Types #define MTP_CONTAINER_TYPE_UNDEFINED 0 #define MTP_CONTAINER_TYPE_COMMAND 1 #define MTP_CONTAINER_TYPE_DATA 2 #define MTP_CONTAINER_TYPE_RESPONSE 3 #define MTP_CONTAINER_TYPE_EVENT 4 // Container Offsets #define MTP_CONTAINER_LENGTH_OFFSET 0 #define MTP_CONTAINER_TYPE_OFFSET 4 #define MTP_CONTAINER_CODE_OFFSET 6 #define MTP_CONTAINER_TRANSACTION_ID_OFFSET 8 #define MTP_CONTAINER_PARAMETER_OFFSET 12 #define MTP_CONTAINER_HEADER_SIZE 12 // MTP Data Types #define MTP_TYPE_UNDEFINED 0x0000 // Undefined #define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer #define MTP_TYPE_UINT8 0x0002 // Unsigned 8-bit integer #define MTP_TYPE_INT16 0x0003 // Signed 16-bit integer #define MTP_TYPE_UINT16 0x0004 // Unsigned 16-bit integer #define MTP_TYPE_INT32 0x0005 // Signed 32-bit integer #define MTP_TYPE_UINT32 0x0006 // Unsigned 32-bit integer #define MTP_TYPE_INT64 0x0007 // Signed 64-bit integer #define MTP_TYPE_UINT64 0x0008 // Unsigned 64-bit integer #define MTP_TYPE_INT128 0x0009 // Signed 128-bit integer #define MTP_TYPE_UINT128 0x000A // Unsigned 128-bit integer #define MTP_TYPE_AINT8 0x4001 // Array of signed 8-bit integers #define MTP_TYPE_AUINT8 0x4002 // Array of unsigned 8-bit integers #define MTP_TYPE_AINT16 0x4003 // Array of signed 16-bit integers #define MTP_TYPE_AUINT16 0x4004 // Array of unsigned 16-bit integers #define MTP_TYPE_AINT32 0x4005 // Array of signed 32-bit integers #define MTP_TYPE_AUINT32 0x4006 // Array of unsigned 32-bit integers #define MTP_TYPE_AINT64 0x4007 // Array of signed 64-bit integers #define MTP_TYPE_AUINT64 0x4008 // Array of unsigned 64-bit integers #define MTP_TYPE_AINT128 0x4009 // Array of signed 128-bit integers #define MTP_TYPE_AUINT128 0x400A // Array of unsigned 128-bit integers #define MTP_TYPE_STR 0xFFFF // Variable-length Unicode string // MTP Format Codes #define MTP_FORMAT_UNDEFINED 0x3000 // Undefined object #define MTP_FORMAT_ASSOCIATION 0x3001 // Association (for example, a folder) #define MTP_FORMAT_SCRIPT 0x3002 // Device model-specific script #define MTP_FORMAT_EXECUTABLE 0x3003 // Device model-specific binary executable #define MTP_FORMAT_TEXT 0x3004 // Text file #define MTP_FORMAT_HTML 0x3005 // Hypertext Markup Language file (text) #define MTP_FORMAT_DPOF 0x3006 // Digital Print Order Format file (text) #define MTP_FORMAT_AIFF 0x3007 // Audio clip #define MTP_FORMAT_WAV 0x3008 // Audio clip #define MTP_FORMAT_MP3 0x3009 // Audio clip #define MTP_FORMAT_AVI 0x300A // Video clip #define MTP_FORMAT_MPEG 0x300B // Video clip #define MTP_FORMAT_ASF 0x300C // Microsoft Advanced Streaming Format (video) #define MTP_FORMAT_DEFINED 0x3800 // Unknown image object #define MTP_FORMAT_EXIF_JPEG 0x3801 // Exchangeable File Format, JEIDA standard #define MTP_FORMAT_TIFF_EP 0x3802 // Tag Image File Format for Electronic Photography #define MTP_FORMAT_FLASHPIX 0x3803 // Structured Storage Image Format #define MTP_FORMAT_BMP 0x3804 // Microsoft Windows Bitmap file #define MTP_FORMAT_CIFF 0x3805 // Canon Camera Image File Format #define MTP_FORMAT_GIF 0x3807 // Graphics Interchange Format #define MTP_FORMAT_JFIF 0x3808 // JPEG File Interchange Format #define MTP_FORMAT_CD 0x3809 // PhotoCD Image Pac #define MTP_FORMAT_PICT 0x380A // Quickdraw Image Format #define MTP_FORMAT_PNG 0x380B // Portable Network Graphics #define MTP_FORMAT_TIFF 0x380D // Tag Image File Format #define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts) #define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format #define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format #define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802 #define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881 #define MTP_FORMAT_UNDEFINED_AUDIO 0xB900 #define MTP_FORMAT_WMA 0xB901 #define MTP_FORMAT_OGG 0xB902 #define MTP_FORMAT_AAC 0xB903 #define MTP_FORMAT_AUDIBLE 0xB904 #define MTP_FORMAT_FLAC 0xB906 #define MTP_FORMAT_UNDEFINED_VIDEO 0xB980 #define MTP_FORMAT_WMV 0xB981 #define MTP_FORMAT_MP4_CONTAINER 0xB982 // ISO 14496-1 #define MTP_FORMAT_MP2 0xB983 #define MTP_FORMAT_3GP_CONTAINER 0xB984 // 3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - \u201cTransparent end-to-end packet switched streaming service, 3GPP file format\u201d). #define MTP_FORMAT_UNDEFINED_COLLECTION 0xBA00 #define MTP_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01 #define MTP_FORMAT_ABSTRACT_IMAGE_ALBUM 0xBA02 #define MTP_FORMAT_ABSTRACT_AUDIO_ALBUM 0xBA03 #define MTP_FORMAT_ABSTRACT_VIDEO_ALBUM 0xBA04 #define MTP_FORMAT_ABSTRACT_AV_PLAYLIST 0xBA05 #define MTP_FORMAT_ABSTRACT_CONTACT_GROUP 0xBA06 #define MTP_FORMAT_ABSTRACT_MESSAGE_FOLDER 0xBA07 #define MTP_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION 0xBA08 #define MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST 0xBA09 #define MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST 0xBA0A #define MTP_FORMAT_ABSTRACT_MEDIACAST 0xBA0B // For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content #define MTP_FORMAT_WPL_PLAYLIST 0xBA10 #define MTP_FORMAT_M3U_PLAYLIST 0xBA11 #define MTP_FORMAT_MPL_PLAYLIST 0xBA12 #define MTP_FORMAT_ASX_PLAYLIST 0xBA13 #define MTP_FORMAT_PLS_PLAYLIST 0xBA14 #define MTP_FORMAT_UNDEFINED_DOCUMENT 0xBA80 #define MTP_FORMAT_ABSTRACT_DOCUMENT 0xBA81 #define MTP_FORMAT_XML_DOCUMENT 0xBA82 #define MTP_FORMAT_MS_WORD_DOCUMENT 0xBA83 #define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT 0xBA84 #define MTP_FORMAT_MS_EXCEL_SPREADSHEET 0xBA85 #define MTP_FORMAT_MS_POWERPOINT_PRESENTATION 0xBA86 #define MTP_FORMAT_UNDEFINED_MESSAGE 0xBB00 #define MTP_FORMAT_ABSTRACT_MESSSAGE 0xBB01 #define MTP_FORMAT_UNDEFINED_CONTACT 0xBB80 #define MTP_FORMAT_ABSTRACT_CONTACT 0xBB81 #define MTP_FORMAT_VCARD_2 0xBB82 // MTP Object Property Codes #define MTP_PROPERTY_STORAGE_ID 0xDC01 #define MTP_PROPERTY_OBJECT_FORMAT 0xDC02 #define MTP_PROPERTY_PROTECTION_STATUS 0xDC03 #define MTP_PROPERTY_OBJECT_SIZE 0xDC04 #define MTP_PROPERTY_ASSOCIATION_TYPE 0xDC05 #define MTP_PROPERTY_ASSOCIATION_DESC 0xDC06 #define MTP_PROPERTY_OBJECT_FILE_NAME 0xDC07 #define MTP_PROPERTY_DATE_CREATED 0xDC08 #define MTP_PROPERTY_DATE_MODIFIED 0xDC09 #define MTP_PROPERTY_KEYWORDS 0xDC0A #define MTP_PROPERTY_PARENT_OBJECT 0xDC0B #define MTP_PROPERTY_ALLOWED_FOLDER_CONTENTS 0xDC0C #define MTP_PROPERTY_HIDDEN 0xDC0D #define MTP_PROPERTY_SYSTEM_OBJECT 0xDC0E #define MTP_PROPERTY_PERSISTENT_UID 0xDC41 #define MTP_PROPERTY_SYNC_ID 0xDC42 #define MTP_PROPERTY_PROPERTY_BAG 0xDC43 #define MTP_PROPERTY_NAME 0xDC44 #define MTP_PROPERTY_CREATED_BY 0xDC45 #define MTP_PROPERTY_ARTIST 0xDC46 #define MTP_PROPERTY_DATE_AUTHORED 0xDC47 #define MTP_PROPERTY_DESCRIPTION 0xDC48 #define MTP_PROPERTY_URL_REFERENCE 0xDC49 #define MTP_PROPERTY_LANGUAGE_LOCALE 0xDC4A #define MTP_PROPERTY_COPYRIGHT_INFORMATION 0xDC4B #define MTP_PROPERTY_SOURCE 0xDC4C #define MTP_PROPERTY_ORIGIN_LOCATION 0xDC4D #define MTP_PROPERTY_DATE_ADDED 0xDC4E #define MTP_PROPERTY_NON_CONSUMABLE 0xDC4F #define MTP_PROPERTY_CORRUPT_UNPLAYABLE 0xDC50 #define MTP_PROPERTY_PRODUCER_SERIAL_NUMBER 0xDC51 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_FORMAT 0xDC81 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_SIZE 0xDC82 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_HEIGHT 0xDC83 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_WIDTH 0xDC84 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DURATION 0xDC85 #define MTP_PROPERTY_REPRESENTATIVE_SAMPLE_DATA 0xDC86 #define MTP_PROPERTY_WIDTH 0xDC87 #define MTP_PROPERTY_HEIGHT 0xDC88 #define MTP_PROPERTY_DURATION 0xDC89 #define MTP_PROPERTY_RATING 0xDC8A #define MTP_PROPERTY_TRACK 0xDC8B #define MTP_PROPERTY_GENRE 0xDC8C #define MTP_PROPERTY_CREDITS 0xDC8D #define MTP_PROPERTY_LYRICS 0xDC8E #define MTP_PROPERTY_SUBSCRIPTION_CONTENT_ID 0xDC8F #define MTP_PROPERTY_PRODUCED_BY 0xDC90 #define MTP_PROPERTY_USE_COUNT 0xDC91 #define MTP_PROPERTY_SKIP_COUNT 0xDC92 #define MTP_PROPERTY_LAST_ACCESSED 0xDC93 #define MTP_PROPERTY_PARENTAL_RATING 0xDC94 #define MTP_PROPERTY_META_GENRE 0xDC95 #define MTP_PROPERTY_COMPOSER 0xDC96 #define MTP_PROPERTY_EFFECTIVE_RATING 0xDC97 #define MTP_PROPERTY_SUBTITLE 0xDC98 #define MTP_PROPERTY_ORIGINAL_RELEASE_DATE 0xDC99 #define MTP_PROPERTY_ALBUM_NAME 0xDC9A #define MTP_PROPERTY_ALBUM_ARTIST 0xDC9B #define MTP_PROPERTY_MOOD 0xDC9C #define MTP_PROPERTY_DRM_STATUS 0xDC9D #define MTP_PROPERTY_SUB_DESCRIPTION 0xDC9E #define MTP_PROPERTY_IS_CROPPED 0xDCD1 #define MTP_PROPERTY_IS_COLOUR_CORRECTED 0xDCD2 #define MTP_PROPERTY_IMAGE_BIT_DEPTH 0xDCD3 #define MTP_PROPERTY_F_NUMBER 0xDCD4 #define MTP_PROPERTY_EXPOSURE_TIME 0xDCD5 #define MTP_PROPERTY_EXPOSURE_INDEX 0xDCD6 #define MTP_PROPERTY_TOTAL_BITRATE 0xDE91 #define MTP_PROPERTY_BITRATE_TYPE 0xDE92 #define MTP_PROPERTY_SAMPLE_RATE 0xDE93 #define MTP_PROPERTY_NUMBER_OF_CHANNELS 0xDE94 #define MTP_PROPERTY_AUDIO_BIT_DEPTH 0xDE95 #define MTP_PROPERTY_SCAN_TYPE 0xDE97 #define MTP_PROPERTY_AUDIO_WAVE_CODEC 0xDE99 #define MTP_PROPERTY_AUDIO_BITRATE 0xDE9A #define MTP_PROPERTY_VIDEO_FOURCC_CODEC 0xDE9B #define MTP_PROPERTY_VIDEO_BITRATE 0xDE9C #define MTP_PROPERTY_FRAMES_PER_THOUSAND_SECONDS 0xDE9D #define MTP_PROPERTY_KEYFRAME_DISTANCE 0xDE9E #define MTP_PROPERTY_BUFFER_SIZE 0xDE9F #define MTP_PROPERTY_ENCODING_QUALITY 0xDEA0 #define MTP_PROPERTY_ENCODING_PROFILE 0xDEA1 #define MTP_PROPERTY_DISPLAY_NAME 0xDCE0 #define MTP_PROPERTY_BODY_TEXT 0xDCE1 #define MTP_PROPERTY_SUBJECT 0xDCE2 #define MTP_PROPERTY_PRIORITY 0xDCE3 #define MTP_PROPERTY_GIVEN_NAME 0xDD00 #define MTP_PROPERTY_MIDDLE_NAMES 0xDD01 #define MTP_PROPERTY_FAMILY_NAME 0xDD02 #define MTP_PROPERTY_PREFIX 0xDD03 #define MTP_PROPERTY_SUFFIX 0xDD04 #define MTP_PROPERTY_PHONETIC_GIVEN_NAME 0xDD05 #define MTP_PROPERTY_PHONETIC_FAMILY_NAME 0xDD06 #define MTP_PROPERTY_EMAIL_PRIMARY 0xDD07 #define MTP_PROPERTY_EMAIL_PERSONAL_1 0xDD08 #define MTP_PROPERTY_EMAIL_PERSONAL_2 0xDD09 #define MTP_PROPERTY_EMAIL_BUSINESS_1 0xDD0A #define MTP_PROPERTY_EMAIL_BUSINESS_2 0xDD0B #define MTP_PROPERTY_EMAIL_OTHERS 0xDD0C #define MTP_PROPERTY_PHONE_NUMBER_PRIMARY 0xDD0D #define MTP_PROPERTY_PHONE_NUMBER_PERSONAL 0xDD0E #define MTP_PROPERTY_PHONE_NUMBER_PERSONAL_2 0xDD0F #define MTP_PROPERTY_PHONE_NUMBER_BUSINESS 0xDD10 #define MTP_PROPERTY_PHONE_NUMBER_BUSINESS_2 0xDD11 #define MTP_PROPERTY_PHONE_NUMBER_MOBILE 0xDD12 #define MTP_PROPERTY_PHONE_NUMBER_MOBILE_2 0xDD13 #define MTP_PROPERTY_FAX_NUMBER_PRIMARY 0xDD14 #define MTP_PROPERTY_FAX_NUMBER_PERSONAL 0xDD15 #define MTP_PROPERTY_FAX_NUMBER_BUSINESS 0xDD16 #define MTP_PROPERTY_PAGER_NUMBER 0xDD17 #define MTP_PROPERTY_PHONE_NUMBER_OTHERS 0xDD18 #define MTP_PROPERTY_PRIMARY_WEB_ADDRESS 0xDD19 #define MTP_PROPERTY_PERSONAL_WEB_ADDRESS 0xDD1A #define MTP_PROPERTY_BUSINESS_WEB_ADDRESS 0xDD1B #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS 0xDD1C #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_2 0xDD1D #define MTP_PROPERTY_INSTANT_MESSANGER_ADDRESS_3 0xDD1E #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_FULL 0xDD1F #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_1 0xDD20 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_LINE_2 0xDD21 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_CITY 0xDD22 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_REGION 0xDD23 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_POSTAL_CODE 0xDD24 #define MTP_PROPERTY_POSTAL_ADDRESS_PERSONAL_COUNTRY 0xDD25 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_FULL 0xDD26 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_1 0xDD27 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_LINE_2 0xDD28 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_CITY 0xDD29 #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_REGION 0xDD2A #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_POSTAL_CODE 0xDD2B #define MTP_PROPERTY_POSTAL_ADDRESS_BUSINESS_COUNTRY 0xDD2C #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_FULL 0xDD2D #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_1 0xDD2E #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_LINE_2 0xDD2F #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_CITY 0xDD30 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_REGION 0xDD31 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_POSTAL_CODE 0xDD32 #define MTP_PROPERTY_POSTAL_ADDRESS_OTHER_COUNTRY 0xDD33 #define MTP_PROPERTY_ORGANIZATION_NAME 0xDD34 #define MTP_PROPERTY_PHONETIC_ORGANIZATION_NAME 0xDD35 #define MTP_PROPERTY_ROLE 0xDD36 #define MTP_PROPERTY_BIRTHDATE 0xDD37 #define MTP_PROPERTY_MESSAGE_TO 0xDD40 #define MTP_PROPERTY_MESSAGE_CC 0xDD41 #define MTP_PROPERTY_MESSAGE_BCC 0xDD42 #define MTP_PROPERTY_MESSAGE_READ 0xDD43 #define MTP_PROPERTY_MESSAGE_RECEIVED_TIME 0xDD44 #define MTP_PROPERTY_MESSAGE_SENDER 0xDD45 #define MTP_PROPERTY_ACTIVITY_BEGIN_TIME 0xDD50 #define MTP_PROPERTY_ACTIVITY_END_TIME 0xDD51 #define MTP_PROPERTY_ACTIVITY_LOCATION 0xDD52 #define MTP_PROPERTY_ACTIVITY_REQUIRED_ATTENDEES 0xDD54 #define MTP_PROPERTY_ACTIVITY_OPTIONAL_ATTENDEES 0xDD55 #define MTP_PROPERTY_ACTIVITY_RESOURCES 0xDD56 #define MTP_PROPERTY_ACTIVITY_ACCEPTED 0xDD57 #define MTP_PROPERTY_ACTIVITY_TENTATIVE 0xDD58 #define MTP_PROPERTY_ACTIVITY_DECLINED 0xDD59 #define MTP_PROPERTY_ACTIVITY_REMAINDER_TIME 0xDD5A #define MTP_PROPERTY_ACTIVITY_OWNER 0xDD5B #define MTP_PROPERTY_ACTIVITY_STATUS 0xDD5C #define MTP_PROPERTY_OWNER 0xDD5D #define MTP_PROPERTY_EDITOR 0xDD5E #define MTP_PROPERTY_WEBMASTER 0xDD5F #define MTP_PROPERTY_URL_SOURCE 0xDD60 #define MTP_PROPERTY_URL_DESTINATION 0xDD61 #define MTP_PROPERTY_TIME_BOOKMARK 0xDD62 #define MTP_PROPERTY_OBJECT_BOOKMARK 0xDD63 #define MTP_PROPERTY_BYTE_BOOKMARK 0xDD64 #define MTP_PROPERTY_LAST_BUILD_DATE 0xDD70 #define MTP_PROPERTY_TIME_TO_LIVE 0xDD71 #define MTP_PROPERTY_MEDIA_GUID 0xDD72 // MTP Device Property Codes #define MTP_DEVICE_PROPERTY_UNDEFINED 0x5000 #define MTP_DEVICE_PROPERTY_BATTERY_LEVEL 0x5001 #define MTP_DEVICE_PROPERTY_FUNCTIONAL_MODE 0x5002 #define MTP_DEVICE_PROPERTY_IMAGE_SIZE 0x5003 #define MTP_DEVICE_PROPERTY_COMPRESSION_SETTING 0x5004 #define MTP_DEVICE_PROPERTY_WHITE_BALANCE 0x5005 #define MTP_DEVICE_PROPERTY_RGB_GAIN 0x5006 #define MTP_DEVICE_PROPERTY_F_NUMBER 0x5007 #define MTP_DEVICE_PROPERTY_FOCAL_LENGTH 0x5008 #define MTP_DEVICE_PROPERTY_FOCUS_DISTANCE 0x5009 #define MTP_DEVICE_PROPERTY_FOCUS_MODE 0x500A #define MTP_DEVICE_PROPERTY_EXPOSURE_METERING_MODE 0x500B #define MTP_DEVICE_PROPERTY_FLASH_MODE 0x500C #define MTP_DEVICE_PROPERTY_EXPOSURE_TIME 0x500D #define MTP_DEVICE_PROPERTY_EXPOSURE_PROGRAM_MODE 0x500E #define MTP_DEVICE_PROPERTY_EXPOSURE_INDEX 0x500F #define MTP_DEVICE_PROPERTY_EXPOSURE_BIAS_COMPENSATION 0x5010 #define MTP_DEVICE_PROPERTY_DATETIME 0x5011 #define MTP_DEVICE_PROPERTY_CAPTURE_DELAY 0x5012 #define MTP_DEVICE_PROPERTY_STILL_CAPTURE_MODE 0x5013 #define MTP_DEVICE_PROPERTY_CONTRAST 0x5014 #define MTP_DEVICE_PROPERTY_SHARPNESS 0x5015 #define MTP_DEVICE_PROPERTY_DIGITAL_ZOOM 0x5016 #define MTP_DEVICE_PROPERTY_EFFECT_MODE 0x5017 #define MTP_DEVICE_PROPERTY_BURST_NUMBER 0x5018 #define MTP_DEVICE_PROPERTY_BURST_INTERVAL 0x5019 #define MTP_DEVICE_PROPERTY_TIMELAPSE_NUMBER 0x501A #define MTP_DEVICE_PROPERTY_TIMELAPSE_INTERVAL 0x501B #define MTP_DEVICE_PROPERTY_FOCUS_METERING_MODE 0x501C #define MTP_DEVICE_PROPERTY_UPLOAD_URL 0x501D #define MTP_DEVICE_PROPERTY_ARTIST 0x501E #define MTP_DEVICE_PROPERTY_COPYRIGHT_INFO 0x501F #define MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER 0xD401 #define MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME 0xD402 #define MTP_DEVICE_PROPERTY_VOLUME 0xD403 #define MTP_DEVICE_PROPERTY_SUPPORTED_FORMATS_ORDERED 0xD404 #define MTP_DEVICE_PROPERTY_DEVICE_ICON 0xD405 #define MTP_DEVICE_PROPERTY_PLAYBACK_RATE 0xD410 #define MTP_DEVICE_PROPERTY_PLAYBACK_OBJECT 0xD411 #define MTP_DEVICE_PROPERTY_PLAYBACK_CONTAINER_INDEX 0xD412 #define MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO 0xD406 #define MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE 0xD407 // MTP Operation Codes #define MTP_OPERATION_GET_DEVICE_INFO 0x1001 #define MTP_OPERATION_OPEN_SESSION 0x1002 #define MTP_OPERATION_CLOSE_SESSION 0x1003 #define MTP_OPERATION_GET_STORAGE_IDS 0x1004 #define MTP_OPERATION_GET_STORAGE_INFO 0x1005 #define MTP_OPERATION_GET_NUM_OBJECTS 0x1006 #define MTP_OPERATION_GET_OBJECT_HANDLES 0x1007 #define MTP_OPERATION_GET_OBJECT_INFO 0x1008 #define MTP_OPERATION_GET_OBJECT 0x1009 #define MTP_OPERATION_GET_THUMB 0x100A #define MTP_OPERATION_DELETE_OBJECT 0x100B #define MTP_OPERATION_SEND_OBJECT_INFO 0x100C #define MTP_OPERATION_SEND_OBJECT 0x100D #define MTP_OPERATION_INITIATE_CAPTURE 0x100E #define MTP_OPERATION_FORMAT_STORE 0x100F #define MTP_OPERATION_RESET_DEVICE 0x1010 #define MTP_OPERATION_SELF_TEST 0x1011 #define MTP_OPERATION_SET_OBJECT_PROTECTION 0x1012 #define MTP_OPERATION_POWER_DOWN 0x1013 #define MTP_OPERATION_GET_DEVICE_PROP_DESC 0x1014 #define MTP_OPERATION_GET_DEVICE_PROP_VALUE 0x1015 #define MTP_OPERATION_SET_DEVICE_PROP_VALUE 0x1016 #define MTP_OPERATION_RESET_DEVICE_PROP_VALUE 0x1017 #define MTP_OPERATION_TERMINATE_OPEN_CAPTURE 0x1018 #define MTP_OPERATION_MOVE_OBJECT 0x1019 #define MTP_OPERATION_COPY_OBJECT 0x101A #define MTP_OPERATION_GET_PARTIAL_OBJECT 0x101B #define MTP_OPERATION_INITIATE_OPEN_CAPTURE 0x101C #define MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED 0x9801 #define MTP_OPERATION_GET_OBJECT_PROP_DESC 0x9802 #define MTP_OPERATION_GET_OBJECT_PROP_VALUE 0x9803 #define MTP_OPERATION_SET_OBJECT_PROP_VALUE 0x9804 #define MTP_OPERATION_GET_OBJECT_PROP_LIST 0x9805 #define MTP_OPERATION_SET_OBJECT_PROP_LIST 0x9806 #define MTP_OPERATION_GET_INTERDEPENDENT_PROP_DESC 0x9807 #define MTP_OPERATION_SEND_OBJECT_PROP_LIST 0x9808 #define MTP_OPERATION_GET_OBJECT_REFERENCES 0x9810 #define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811 #define MTP_OPERATION_SKIP 0x9820 // Android extensions for direct file IO // Same as GetPartialObject, but with 64 bit offset #define MTP_OPERATION_GET_PARTIAL_OBJECT_64 0x95C1 // Same as GetPartialObject64, but copying host to device #define MTP_OPERATION_SEND_PARTIAL_OBJECT 0x95C2 // Truncates file to 64 bit length #define MTP_OPERATION_TRUNCATE_OBJECT 0x95C3 // Must be called before using SendPartialObject and TruncateObject #define MTP_OPERATION_BEGIN_EDIT_OBJECT 0x95C4 // Called to commit changes made by SendPartialObject and TruncateObject #define MTP_OPERATION_END_EDIT_OBJECT 0x95C5 // MTP Response Codes #define MTP_RESPONSE_UNDEFINED 0x2000 #define MTP_RESPONSE_OK 0x2001 #define MTP_RESPONSE_GENERAL_ERROR 0x2002 #define MTP_RESPONSE_SESSION_NOT_OPEN 0x2003 #define MTP_RESPONSE_INVALID_TRANSACTION_ID 0x2004 #define MTP_RESPONSE_OPERATION_NOT_SUPPORTED 0x2005 #define MTP_RESPONSE_PARAMETER_NOT_SUPPORTED 0x2006 #define MTP_RESPONSE_INCOMPLETE_TRANSFER 0x2007 #define MTP_RESPONSE_INVALID_STORAGE_ID 0x2008 #define MTP_RESPONSE_INVALID_OBJECT_HANDLE 0x2009 #define MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED 0x200A #define MTP_RESPONSE_INVALID_OBJECT_FORMAT_CODE 0x200B #define MTP_RESPONSE_STORAGE_FULL 0x200C #define MTP_RESPONSE_OBJECT_WRITE_PROTECTED 0x200D #define MTP_RESPONSE_STORE_READ_ONLY 0x200E #define MTP_RESPONSE_ACCESS_DENIED 0x200F #define MTP_RESPONSE_NO_THUMBNAIL_PRESENT 0x2010 #define MTP_RESPONSE_SELF_TEST_FAILED 0x2011 #define MTP_RESPONSE_PARTIAL_DELETION 0x2012 #define MTP_RESPONSE_STORE_NOT_AVAILABLE 0x2013 #define MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED 0x2014 #define MTP_RESPONSE_NO_VALID_OBJECT_INFO 0x2015 #define MTP_RESPONSE_INVALID_CODE_FORMAT 0x2016 #define MTP_RESPONSE_UNKNOWN_VENDOR_CODE 0x2017 #define MTP_RESPONSE_CAPTURE_ALREADY_TERMINATED 0x2018 #define MTP_RESPONSE_DEVICE_BUSY 0x2019 #define MTP_RESPONSE_INVALID_PARENT_OBJECT 0x201A #define MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT 0x201B #define MTP_RESPONSE_INVALID_DEVICE_PROP_VALUE 0x201C #define MTP_RESPONSE_INVALID_PARAMETER 0x201D #define MTP_RESPONSE_SESSION_ALREADY_OPEN 0x201E #define MTP_RESPONSE_TRANSACTION_CANCELLED 0x201F #define MTP_RESPONSE_SPECIFICATION_OF_DESTINATION_UNSUPPORTED 0x2020 #define MTP_RESPONSE_INVALID_OBJECT_PROP_CODE 0xA801 #define MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT 0xA802 #define MTP_RESPONSE_INVALID_OBJECT_PROP_VALUE 0xA803 #define MTP_RESPONSE_INVALID_OBJECT_REFERENCE 0xA804 #define MTP_RESPONSE_GROUP_NOT_SUPPORTED 0xA805 #define MTP_RESPONSE_INVALID_DATASET 0xA806 #define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED 0xA807 #define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED 0xA808 #define MTP_RESPONSE_OBJECT_TOO_LARGE 0xA809 #define MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED 0xA80A // MTP Event Codes #define MTP_EVENT_UNDEFINED 0x4000 #define MTP_EVENT_CANCEL_TRANSACTION 0x4001 #define MTP_EVENT_OBJECT_ADDED 0x4002 #define MTP_EVENT_OBJECT_REMOVED 0x4003 #define MTP_EVENT_STORE_ADDED 0x4004 #define MTP_EVENT_STORE_REMOVED 0x4005 #define MTP_EVENT_DEVICE_PROP_CHANGED 0x4006 #define MTP_EVENT_OBJECT_INFO_CHANGED 0x4007 #define MTP_EVENT_DEVICE_INFO_CHANGED 0x4008 #define MTP_EVENT_REQUEST_OBJECT_TRANSFER 0x4009 #define MTP_EVENT_STORE_FULL 0x400A #define MTP_EVENT_DEVICE_RESET 0x400B #define MTP_EVENT_STORAGE_INFO_CHANGED 0x400C #define MTP_EVENT_CAPTURE_COMPLETE 0x400D #define MTP_EVENT_UNREPORTED_STATUS 0x400E #define MTP_EVENT_OBJECT_PROP_CHANGED 0xC801 #define MTP_EVENT_OBJECT_PROP_DESC_CHANGED 0xC802 #define MTP_EVENT_OBJECT_REFERENCES_CHANGED 0xC803 // Storage Type #define MTP_STORAGE_FIXED_ROM 0x0001 #define MTP_STORAGE_REMOVABLE_ROM 0x0002 #define MTP_STORAGE_FIXED_RAM 0x0003 #define MTP_STORAGE_REMOVABLE_RAM 0x0004 // Storage File System #define MTP_STORAGE_FILESYSTEM_FLAT 0x0001 #define MTP_STORAGE_FILESYSTEM_HIERARCHICAL 0x0002 #define MTP_STORAGE_FILESYSTEM_DCF 0x0003 // Storage Access Capability #define MTP_STORAGE_READ_WRITE 0x0000 #define MTP_STORAGE_READ_ONLY_WITHOUT_DELETE 0x0001 #define MTP_STORAGE_READ_ONLY_WITH_DELETE 0x0002 // Association Type #define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000 #define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001 #endif // _MTP_H mtp-0.0.3+14.04.20140409/include/MtpObjectInfo.h0000644000015301777760000000341512321133655021216 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_OBJECT_INFO_H #define _MTP_OBJECT_INFO_H #include "MtpTypes.h" namespace android { class MtpDataPacket; class MtpObjectInfo { public: MtpObjectHandle mHandle; MtpStorageID mStorageID; MtpObjectFormat mFormat; uint16_t mProtectionStatus; uint32_t mCompressedSize; MtpObjectFormat mThumbFormat; uint32_t mThumbCompressedSize; uint32_t mThumbPixWidth; uint32_t mThumbPixHeight; uint32_t mImagePixWidth; uint32_t mImagePixHeight; uint32_t mImagePixDepth; MtpObjectHandle mParent; uint16_t mAssociationType; uint32_t mAssociationDesc; uint32_t mSequenceNumber; char* mName; time_t mDateCreated; time_t mDateModified; char* mKeywords; public: MtpObjectInfo(MtpObjectHandle handle); virtual ~MtpObjectInfo(); void read(MtpDataPacket& packet); void print(); }; }; // namespace android #endif // _MTP_OBJECT_INFO_H mtp-0.0.3+14.04.20140409/include/MtpRequestPacket.h0000644000015301777760000000270012321133655021750 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_REQUEST_PACKET_H #define _MTP_REQUEST_PACKET_H #include "MtpPacket.h" #include "mtp.h" struct usb_request; namespace android { class MtpRequestPacket : public MtpPacket { public: MtpRequestPacket(); virtual ~MtpRequestPacket(); #ifdef MTP_DEVICE // fill our buffer with data from the given file descriptor int read(int fd); #endif #ifdef MTP_HOST // write our buffer to the given endpoint int write(struct usb_request *request); #endif inline MtpOperationCode getOperationCode() const { return getContainerCode(); } inline void setOperationCode(MtpOperationCode code) { return setContainerCode(code); } }; }; // namespace android #endif // _MTP_REQUEST_PACKET_H mtp-0.0.3+14.04.20140409/include/MtpServer.h0000644000015301777760000001310412321133655020436 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_SERVER_H #define _MTP_SERVER_H #include "MtpRequestPacket.h" #include "MtpDataPacket.h" #include "MtpResponsePacket.h" #include "MtpEventPacket.h" #include "mtp.h" #include "MtpUtils.h" #include namespace android { class MtpDatabase; class MtpStorage; class MtpServer { private: // file descriptor for MTP kernel driver int mFD; MtpDatabase* mDatabase; // appear as a PTP device bool mPtp; // group to own new files and folders int mFileGroup; // permissions for new files and directories int mFilePermission; int mDirectoryPermission; // current session ID MtpSessionID mSessionID; // true if we have an open session and mSessionID is valid bool mSessionOpen; MtpRequestPacket mRequest; MtpDataPacket mData; MtpResponsePacket mResponse; MtpEventPacket mEvent; MtpStorageList mStorages; // handle for new object, set by SendObjectInfo and used by SendObject MtpObjectHandle mSendObjectHandle; MtpObjectFormat mSendObjectFormat; MtpString mSendObjectFilePath; size_t mSendObjectFileSize; MtpMutex mMutex; // represents an MTP object that is being edited using the android extensions // for direct editing (BeginEditObject, SendPartialObject, TruncateObject and EndEditObject) class ObjectEdit { public: MtpObjectHandle mHandle; MtpString mPath; uint64_t mSize; MtpObjectFormat mFormat; int mFD; ObjectEdit(MtpObjectHandle handle, const MtpString& path, uint64_t size, MtpObjectFormat format, int fd) : mHandle(handle), mPath(path), mSize(size), mFormat(format), mFD(fd) { } virtual ~ObjectEdit() { close(mFD); } }; Vector mObjectEditList; public: MtpServer(int fd, MtpDatabase* database, bool ptp, int fileGroup, int filePerm, int directoryPerm); virtual ~MtpServer(); MtpStorage* getStorage(MtpStorageID id); inline bool hasStorage() { return mStorages.size() > 0; } bool hasStorage(MtpStorageID id); void addStorage(MtpStorage* storage); void removeStorage(MtpStorage* storage); void run(); void sendObjectAdded(MtpObjectHandle handle); void sendObjectRemoved(MtpObjectHandle handle); void sendObjectInfoChanged(MtpObjectHandle handle); void sendObjectPropChanged(MtpObjectHandle handle, MtpObjectProperty prop); private: void sendStoreAdded(MtpStorageID id); void sendStoreRemoved(MtpStorageID id); void sendEvent(MtpEventCode code, uint32_t param1, uint32_t param2, uint32_t param3); void addEditObject(MtpObjectHandle handle, MtpString& path, uint64_t size, MtpObjectFormat format, int fd); ObjectEdit* getEditObject(MtpObjectHandle handle); void removeEditObject(MtpObjectHandle handle); void commitEdit(ObjectEdit* edit); bool handleRequest(); MtpResponseCode doGetDeviceInfo(); MtpResponseCode doOpenSession(); MtpResponseCode doCloseSession(); MtpResponseCode doGetStorageIDs(); MtpResponseCode doGetStorageInfo(); MtpResponseCode doGetObjectPropsSupported(); MtpResponseCode doGetObjectHandles(); MtpResponseCode doGetNumObjects(); MtpResponseCode doGetObjectReferences(); MtpResponseCode doSetObjectReferences(); MtpResponseCode doGetObjectPropValue(); MtpResponseCode doSetObjectPropValue(); MtpResponseCode doGetDevicePropValue(); MtpResponseCode doSetDevicePropValue(); MtpResponseCode doResetDevicePropValue(); MtpResponseCode doGetObjectPropList(); MtpResponseCode doGetObjectInfo(); MtpResponseCode doGetObject(); MtpResponseCode doGetThumb(); MtpResponseCode doGetPartialObject(MtpOperationCode operation); MtpResponseCode doSendObjectInfo(); MtpResponseCode doSendObject(); MtpResponseCode doDeleteObject(); MtpResponseCode doMoveObject(); MtpResponseCode doGetObjectPropDesc(); MtpResponseCode doGetDevicePropDesc(); MtpResponseCode doSendPartialObject(); MtpResponseCode doTruncateObject(); MtpResponseCode doBeginEditObject(); MtpResponseCode doEndEditObject(); }; }; // namespace android #endif // _MTP_SERVER_H mtp-0.0.3+14.04.20140409/include/MtpDevice.h0000644000015301777760000001026212321133655020371 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_DEVICE_H #define _MTP_DEVICE_H #include "MtpRequestPacket.h" #include "MtpDataPacket.h" #include "MtpResponsePacket.h" #include "MtpTypes.h" struct usb_device; struct usb_request; struct usb_endpoint_descriptor; namespace android { class MtpDeviceInfo; class MtpObjectInfo; class MtpStorageInfo; class MtpDevice { private: struct usb_device* mDevice; int mInterface; struct usb_request* mRequestIn1; struct usb_request* mRequestIn2; struct usb_request* mRequestOut; struct usb_request* mRequestIntr; MtpDeviceInfo* mDeviceInfo; MtpPropertyList mDeviceProperties; // current session ID MtpSessionID mSessionID; // current transaction ID MtpTransactionID mTransactionID; MtpRequestPacket mRequest; MtpDataPacket mData; MtpResponsePacket mResponse; // set to true if we received a response packet instead of a data packet bool mReceivedResponse; // to ensure only one MTP transaction at a time MtpMutex mMutex; public: MtpDevice(struct usb_device* device, int interface, const struct usb_endpoint_descriptor *ep_in, const struct usb_endpoint_descriptor *ep_out, const struct usb_endpoint_descriptor *ep_intr); static MtpDevice* open(const char* deviceName, int fd); virtual ~MtpDevice(); void initialize(); void close(); void print(); const char* getDeviceName(); bool openSession(); bool closeSession(); MtpDeviceInfo* getDeviceInfo(); MtpStorageIDList* getStorageIDs(); MtpStorageInfo* getStorageInfo(MtpStorageID storageID); MtpObjectHandleList* getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent); MtpObjectInfo* getObjectInfo(MtpObjectHandle handle); void* getThumbnail(MtpObjectHandle handle, int& outLength); MtpObjectHandle sendObjectInfo(MtpObjectInfo* info); bool sendObject(MtpObjectInfo* info, int srcFD); bool deleteObject(MtpObjectHandle handle); MtpObjectHandle getParent(MtpObjectHandle handle); MtpObjectHandle getStorageID(MtpObjectHandle handle); MtpObjectPropertyList* getObjectPropsSupported(MtpObjectFormat format); MtpProperty* getDevicePropDesc(MtpDeviceProperty code); MtpProperty* getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format); bool readObject(MtpObjectHandle handle, bool (* callback)(void* data, int offset, int length, void* clientData), int objectSize, void* clientData); bool readObject(MtpObjectHandle handle, const char* destPath, int group, int perm); private: bool sendRequest(MtpOperationCode operation); bool sendData(); bool readData(); bool writeDataHeader(MtpOperationCode operation, int dataLength); MtpResponseCode readResponse(); }; }; // namespace android #endif // _MTP_DEVICE_H mtp-0.0.3+14.04.20140409/include/MtpTypes.h0000644000015301777760000000507512321133675020306 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_TYPES_H #define _MTP_TYPES_H #include #include #include #include #include #include namespace android { typedef int32_t int128_t[4]; typedef uint32_t uint128_t[4]; typedef uint16_t MtpOperationCode; typedef uint16_t MtpResponseCode; typedef uint16_t MtpEventCode; typedef uint32_t MtpSessionID; typedef uint32_t MtpStorageID; typedef uint32_t MtpTransactionID; typedef uint16_t MtpPropertyCode; typedef uint16_t MtpDataType; typedef uint16_t MtpObjectFormat; typedef MtpPropertyCode MtpDeviceProperty; typedef MtpPropertyCode MtpObjectProperty; // object handles are unique across all storage but only within a single session. // object handles cannot be reused after an object is deleted. // values 0x00000000 and 0xFFFFFFFF are reserved for special purposes. typedef uint32_t MtpObjectHandle; // Special values #define MTP_PARENT_ROOT 0xFFFFFFFF // parent is root of the storage #define kInvalidObjectHandle 0xFFFFFFFF class MtpStorage; class MtpDevice; class MtpProperty; template using Vector = std::vector; typedef std::vector MtpStorageList; typedef std::vector MtpDeviceList; typedef std::vector MtpPropertyList; typedef std::vector UInt8List; typedef std::vector UInt16List; typedef std::vector UInt32List; typedef std::vector UInt64List; typedef std::vector Int8List; typedef std::vector Int16List; typedef std::vector Int32List; typedef std::vector Int64List; typedef UInt16List MtpObjectPropertyList; typedef UInt16List MtpDevicePropertyList; typedef UInt16List MtpObjectFormatList; typedef UInt32List MtpObjectHandleList; typedef UInt16List MtpObjectPropertyList; typedef UInt32List MtpStorageIDList; typedef std::string MtpString; typedef std::mutex MtpMutex; typedef std::lock_guard MtpAutolock; }; // namespace android #endif // _MTP_TYPES_H mtp-0.0.3+14.04.20140409/include/linux/0000755000015301777760000000000012321134053017467 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/include/linux/usb/0000755000015301777760000000000012321134053020260 5ustar pbusernogroup00000000000000mtp-0.0.3+14.04.20140409/include/linux/usb/f_mtp.h0000644000015301777760000000406512321133655021552 0ustar pbusernogroup00000000000000/* * Gadget Function Driver for MTP * * Copyright (C) 2010 Google, Inc. * Author: Mike Lockwood * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #ifndef __LINUX_USB_F_MTP_H #define __LINUX_USB_F_MTP_H #ifdef __KERNEL__ struct mtp_data_header { /* length of packet, including this header */ uint32_t length; /* container type (2 for data packet) */ uint16_t type; /* MTP command code */ uint16_t command; /* MTP transaction ID */ uint32_t transaction_id; }; #endif /* __KERNEL__ */ struct mtp_file_range { /* file descriptor for file to transfer */ int fd; /* offset in file for start of transfer */ loff_t offset; /* number of bytes to transfer */ int64_t length; /* MTP command ID for data header, * used only for MTP_SEND_FILE_WITH_HEADER */ uint16_t command; /* MTP transaction ID for data header, * used only for MTP_SEND_FILE_WITH_HEADER */ uint32_t transaction_id; }; struct mtp_event { /* size of the event */ size_t length; /* event data to send */ void *data; }; /* Sends the specified file range to the host */ #define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) /* Receives data from the host and writes it to a file. * The file is created if it does not exist. */ #define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) /* Sends an event to the host via the interrupt endpoint */ #define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) /* Sends the specified file range to the host, * with a 12 byte MTP data packet header at the beginning. */ #define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range) #endif /* __LINUX_USB_F_MTP_H */ mtp-0.0.3+14.04.20140409/include/MtpDatabase.h0000644000015301777760000001224512321133675020703 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_DATABASE_H #define _MTP_DATABASE_H #include "MtpTypes.h" #include "MtpServer.h" namespace android { class MtpDataPacket; class MtpProperty; class MtpObjectInfo; class MtpDatabase { public: virtual ~MtpDatabase() {} // called from SendObjectInfo to reserve a database entry for the incoming file virtual MtpObjectHandle beginSendObject(const MtpString& path, MtpObjectFormat format, MtpObjectHandle parent, MtpStorageID storage, uint64_t size, time_t modified) = 0; // called to report success or failure of the SendObject file transfer // success should signal a notification of the new object's creation, // failure should remove the database entry created in beginSendObject virtual void endSendObject(const MtpString& path, MtpObjectHandle handle, MtpObjectFormat format, bool succeeded) = 0; virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) = 0; virtual int getNumObjects(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent) = 0; // callee should delete[] the results from these // results can be NULL virtual MtpObjectFormatList* getSupportedPlaybackFormats() = 0; virtual MtpObjectFormatList* getSupportedCaptureFormats() = 0; virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format) = 0; virtual MtpDevicePropertyList* getSupportedDeviceProperties() = 0; virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) = 0; virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) = 0; virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) = 0; virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) = 0; virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property) = 0; virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) = 0; virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) = 0; virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) = 0; virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) = 0; virtual MtpResponseCode deleteFile(MtpObjectHandle handle) = 0; virtual MtpResponseCode moveFile(MtpObjectHandle handle, MtpObjectHandle new_parent) = 0; virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle) = 0; virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle, MtpObjectHandleList* references) = 0; virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property, MtpObjectFormat format) = 0; virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0; virtual void sessionStarted(MtpServer* server) = 0; virtual void sessionEnded() = 0; }; }; // namespace android #endif // _MTP_DATABASE_H mtp-0.0.3+14.04.20140409/include/MtpDeviceInfo.h0000644000015301777760000000313512321133655021206 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_DEVICE_INFO_H #define _MTP_DEVICE_INFO_H struct stat; namespace android { class MtpDataPacket; class MtpDeviceInfo { public: uint16_t mStandardVersion; uint32_t mVendorExtensionID; uint16_t mVendorExtensionVersion; char* mVendorExtensionDesc; uint16_t mFunctionalCode; UInt16List* mOperations; UInt16List* mEvents; MtpDevicePropertyList* mDeviceProperties; MtpObjectFormatList* mCaptureFormats; MtpObjectFormatList* mPlaybackFormats; char* mManufacturer; char* mModel; char* mVersion; char* mSerial; public: MtpDeviceInfo(); virtual ~MtpDeviceInfo(); void read(MtpDataPacket& packet); void print(); }; }; // namespace android #endif // _MTP_DEVICE_INFO_H mtp-0.0.3+14.04.20140409/include/MtpDataPacket.h0000644000015301777760000001164712321133655021203 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _MTP_DATA_PACKET_H #define _MTP_DATA_PACKET_H #include "MtpPacket.h" #include "mtp.h" struct usb_device; struct usb_request; namespace android { class MtpStringBuffer; class MtpDataPacket : public MtpPacket { private: // current offset for get/put methods int mOffset; public: MtpDataPacket(); virtual ~MtpDataPacket(); virtual void reset(); void setOperationCode(MtpOperationCode code); void setTransactionID(MtpTransactionID id); inline const uint8_t* getData() const { return mBuffer + MTP_CONTAINER_HEADER_SIZE; } inline uint8_t getUInt8() { return (uint8_t)mBuffer[mOffset++]; } inline int8_t getInt8() { return (int8_t)mBuffer[mOffset++]; } uint16_t getUInt16(); inline int16_t getInt16() { return (int16_t)getUInt16(); } uint32_t getUInt32(); inline int32_t getInt32() { return (int32_t)getUInt32(); } uint64_t getUInt64(); inline int64_t getInt64() { return (int64_t)getUInt64(); } void getUInt128(uint128_t& value); inline void getInt128(int128_t& value) { getUInt128((uint128_t&)value); } void getString(MtpStringBuffer& string); Int8List* getAInt8(); UInt8List* getAUInt8(); Int16List* getAInt16(); UInt16List* getAUInt16(); Int32List* getAInt32(); UInt32List* getAUInt32(); Int64List* getAInt64(); UInt64List* getAUInt64(); void putInt8(int8_t value); void putUInt8(uint8_t value); void putInt16(int16_t value); void putUInt16(uint16_t value); void putInt32(int32_t value); void putUInt32(uint32_t value); void putInt64(int64_t value); void putUInt64(uint64_t value); void putInt128(const int128_t& value); void putUInt128(const uint128_t& value); void putInt128(int64_t value); void putUInt128(uint64_t value); void putAInt8(const int8_t* values, int count); void putAUInt8(const uint8_t* values, int count); void putAInt16(const int16_t* values, int count); void putAUInt16(const uint16_t* values, int count); void putAUInt16(const UInt16List* values); void putAInt32(const int32_t* values, int count); void putAUInt32(const uint32_t* values, int count); void putAUInt32(const UInt32List* list); void putAInt64(const int64_t* values, int count); void putAUInt64(const uint64_t* values, int count); void putString(const MtpStringBuffer& string); void putString(const char* string); void putString(const uint16_t* string); inline void putEmptyString() { putUInt8(0); } inline void putEmptyArray() { putUInt32(0); } #ifdef MTP_DEVICE // fill our buffer with data from the given file descriptor int read(int fd); // write our data to the given file descriptor int write(int fd); int writeData(int fd, void* data, uint32_t length); #endif #ifdef MTP_HOST int read(struct usb_request *request); int readData(struct usb_request *request, void* buffer, int length); int readDataAsync(struct usb_request *req); int readDataWait(struct usb_device *device); int readDataHeader(struct usb_request *ep); int writeDataHeader(struct usb_request *ep, uint32_t length); int write(struct usb_request *ep); int write(struct usb_request *ep, void* buffer, uint32_t length); #endif inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; } inline uint32_t getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); } void* getData(int& outLength) const; }; }; // namespace android #endif // _MTP_DATA_PACKET_H