add mtp responder to TWRP.
Big thanks to Dees_Troy for helping with the implementation.

Change-Id: I6c9c522b9c9de5dc139e2ecb0141008182ba07f0
diff --git a/Android.mk b/Android.mk
index 921a84b..ea6bb57 100644
--- a/Android.mk
+++ b/Android.mk
@@ -73,7 +73,8 @@
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_STATIC_LIBRARIES += libcrecovery libguitwrp
-LOCAL_SHARED_LIBRARIES += libz libc libstlport libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery
+LOCAL_SHARED_LIBRARIES += libz libc libstlport libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery libcorkscrew
+LOCAL_SHARED_LIBRARIES += libgccdemangle
 
 ifneq ($(wildcard system/core/libsparse/Android.mk),)
 LOCAL_SHARED_LIBRARIES += libsparse
@@ -84,6 +85,7 @@
     BOARD_HAS_NO_REAL_SDCARD := true
     TW_USE_TOOLBOX := true
     TW_EXCLUDE_SUPERSU := true
+    TW_EXCLUDE_MTP := true
 endif
 ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
     LOCAL_CFLAGS += -DUSE_EXT4
@@ -124,6 +126,10 @@
 LOCAL_C_INCLUDES += system/extras/ext4_utils
 
 #TWRP Build Flags
+ifeq ($(TW_EXCLUDE_MTP),)
+    LOCAL_SHARED_LIBRARIES += libtwrpmtp
+    LOCAL_CFLAGS += -DTW_HAS_MTP
+endif
 ifneq ($(TW_NO_SCREEN_TIMEOUT),)
     LOCAL_CFLAGS += -DTW_NO_SCREEN_TIMEOUT
 endif
@@ -373,7 +379,8 @@
     $(commands_recovery_local_path)/openaes/Android.mk \
     $(commands_recovery_local_path)/toolbox/Android.mk \
     $(commands_recovery_local_path)/libmincrypt/Android.mk \
-    $(commands_recovery_local_path)/twrpTarMain/Android.mk
+    $(commands_recovery_local_path)/twrpTarMain/Android.mk \
+    $(commands_recovery_local_path)/mtp/Android.mk
 
 ifeq ($(TW_INCLUDE_CRYPTO_SAMSUNG), true)
     include $(commands_recovery_local_path)/crypto/libcrypt_samsung/Android.mk
@@ -411,5 +418,3 @@
 ifeq ($(TW_INCLUDE_FB2PNG), true)
     include $(commands_recovery_local_path)/fb2png/Android.mk
 endif
-
-commands_recovery_local_path :=
diff --git a/data.cpp b/data.cpp
index afa676d..7b85d2c 100644
--- a/data.cpp
+++ b/data.cpp
@@ -996,6 +996,14 @@
 	LOGINFO("TW_EXCLUDE_ENCRYPTED_BACKUPS := true\n");
 	mValues.insert(make_pair("tw_include_encrypted_backup", make_pair("0", 0)));
 #endif
+#ifdef TW_HAS_MTP
+	mConstValues.insert(make_pair("tw_has_mtp", "1"));
+	mValues.insert(make_pair("tw_mtp_enabled", make_pair("1", 1)));
+#else
+	LOGINFO("TW_EXCLUDE_MTP := true\n");
+	mConstValues.insert(make_pair("tw_has_mtp", "0"));
+	mConstValues.insert(make_pair("tw_mtp_enabled", "0"));
+#endif
 }
 
 // Magic Values
diff --git a/etc/init.rc b/etc/init.rc
index 39724d0..dda009b 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -23,7 +23,7 @@
 
     write /sys/class/android_usb/android0/enable 0
     write /sys/class/android_usb/android0/idVendor 18D1
-    write /sys/class/android_usb/android0/idProduct D001
+    write /sys/class/android_usb/android0/idProduct D002
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
     write /sys/class/android_usb/android0/iProduct ${ro.product.model}
@@ -51,6 +51,25 @@
     write /sys/class/android_usb/android0/functions adb
     write /sys/class/android_usb/android0/enable ${service.adb.root}
 
+on property:sys.usb.config=none
+    stop adbd
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/bDeviceClass 0
+
+on property:sys.usb.config=mtp,adb
+    stop adbd
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/functions mtp,adb
+    write /sys/class/android_usb/android0/enable 1
+    start adbd
+
+on property:sys.usb.config=adb
+    stop adbd
+    write /sys/class/android_usb/android0/enable 0
+    write /sys/class/android_usb/android0/functions adb
+    write /sys/class/android_usb/android0/enable ${service.adb.root}
+    start adbd
+
 service ueventd /sbin/ueventd
     critical
 
@@ -73,4 +92,4 @@
 on property:service.adb.root=1
     write /sys/class/android_usb/android0/enable 0
     restart adbd
-    write /sys/class/android_usb/android0/enable 1
+    write /sys/class/android_usb/android0/enable 1
\ No newline at end of file
diff --git a/gui/Android.mk b/gui/Android.mk
index b172b2b..3e499ab 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -62,7 +62,7 @@
 ifeq ($(HAVE_SELINUX), true)
 LOCAL_CFLAGS += -DHAVE_SELINUX
 endif
-ifeq ($(TW_OEM_BUILD),true)
+ifeq ($(TW_OEM_BUILD), true)
     LOCAL_CFLAGS += -DTW_OEM_BUILD
 endif
 
diff --git a/gui/action.cpp b/gui/action.cpp
index c471533..7e43222 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -1305,7 +1305,6 @@
 				} else {
 					ret = 1; // failure
 				}
-				PartitionManager.Update_System_Details();
 				if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) {
 					operation_start("ReinjectTWRP");
 					gui_print("Injecting TWRP into boot image...\n");
@@ -1469,6 +1468,32 @@
 			operation_end(op_status, simulate);
 			return 0;
 		}
+		if (function == "startmtp")
+		{
+			int op_status = 0;
+
+			operation_start("Start MTP");
+			if (PartitionManager.Enable_MTP())
+				op_status = 0; // success
+			else
+				op_status = 1; // fail
+
+			operation_end(op_status, simulate);
+			return 0;
+		}
+		if (function == "stopmtp")
+		{
+			int op_status = 0;
+
+			operation_start("Stop MTP");
+			if (PartitionManager.Disable_MTP())
+				op_status = 0; // success
+			else
+				op_status = 1; // fail
+
+			operation_end(op_status, simulate);
+			return 0;
+		}
 	}
 	else
 	{
diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml
index 2bed2a5..aea32f1 100644
--- a/gui/devices/landscape/res/landscape.xml
+++ b/gui/devices/landscape/res/landscape.xml
@@ -903,6 +903,45 @@
 
 			<object type="button">
 				<highlight color="%highlight_color%" />
+				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="0" />
+				</conditions>
+				<placement x="%col3_x%" y="row1_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Enable MTP</text>
+				<image resource="main_button" />
+				<action function="startmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="1" />
+				</conditions>
+				<placement x="%col3_x%" y="row1_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Disable MTP</text>
+				<image resource="main_button" />
+				<action function="stopmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
+					<condition var1="tw_is_encrypted" var2="1" />
+					<condition var1="tw_is_decrypted" var2="0" />
+				</conditions>
+				<placement x="%col3_x%" y="row1_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Decrypt Data</text>
+				<image resource="main_button" />
+				<action function="page">decrypt</action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
 				<fill color="%button_fill_color%" />
 				<placement x="%col3_x%" y="%backup_storage_y%" w="%button_fill_main_width%" h="%button_fill_half_height%" />
 				<font resource="font" color="%button_text_color%" />
diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml
index 0be6855..e07a217 100644
--- a/gui/devices/portrait/res/portrait.xml
+++ b/gui/devices/portrait/res/portrait.xml
@@ -2146,6 +2146,32 @@
 			<object type="button">
 				<highlight color="%highlight_color%" />
 				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="0" />
+				</conditions>
+				<placement x="%col2_x%" y="row4_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Enable MTP</text>
+				<image resource="main_button" />
+				<action function="startmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="1" />
+				</conditions>
+				<placement x="%col2_x%" y="row4_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Disable MTP</text>
+				<image resource="main_button" />
+				<action function="stopmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
 					<condition var1="tw_is_encrypted" var2="1" />
 					<condition var1="tw_is_decrypted" var2="0" />
 				</conditions>
@@ -2201,6 +2227,7 @@
 
 			<object type="action">
 				<action function="mount">usb</action>
+				<action function="set">tw_busy=1</action>
 			</object>
 
 			<object type="template" name="footer" />
@@ -2213,6 +2240,7 @@
 
 			<object type="action">
 				<action function="page">mount</action>
+				<action function="set">tw_busy=0</action>
 			</object>
 		</page>
 
diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml
index 686b24b..00f449e 100644
--- a/gui/devices/watch/res/watch.xml
+++ b/gui/devices/watch/res/watch.xml
@@ -2118,6 +2118,32 @@
 			<object type="button">
 				<highlight color="%highlight_color%" />
 				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="0" />
+				</conditions>
+				<placement x="%col2_x%" y="row4_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Enable MTP</text>
+				<image resource="main_button" />
+				<action function="startmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
+					<condition var1="tw_has_mtp" var2="1" />
+					<condition var1="tw_mtp_enabled" var2="1" />
+				</conditions>
+				<placement x="%col2_x%" y="row4_y" />
+				<font resource="font" color="%button_text_color%" />
+				<text>Disable MTP</text>
+				<image resource="main_button" />
+				<action function="stopmtp"></action>
+			</object>
+
+			<object type="button">
+				<highlight color="%highlight_color%" />
+				<conditions>
 					<condition var1="tw_is_encrypted" var2="1" />
 					<condition var1="tw_is_decrypted" var2="0" />
 				</conditions>
diff --git a/mtp/Android.mk b/mtp/Android.mk
new file mode 100755
index 0000000..ebf1a6d
--- /dev/null
+++ b/mtp/Android.mk
@@ -0,0 +1,65 @@
+LOCAL_PATH := $(call my-dir)
+
+# Build libtwrpmtp library
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libtwrpmtp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DMTP_DEVICE -DMTP_HOST
+LOCAL_C_INCLUDES += $(LOCAL_PATH) bionic external/stlport/stlport frameworks/base/include system/core/include bionic/libc/private/
+LOCAL_SRC_FILES = \
+    btree.cpp \
+    MtpDataPacket.cpp \
+    MtpDebug.cpp \
+    MtpDevice.cpp \
+    MtpDeviceInfo.cpp \
+    MtpEventPacket.cpp \
+    MtpObjectInfo.cpp \
+    MtpPacket.cpp \
+    MtpProperty.cpp \
+    MtpRequestPacket.cpp \
+    MtpResponsePacket.cpp \
+    MtpServer.cpp \
+    MtpStorage.cpp \
+    MtpStorageInfo.cpp \
+    MtpStringBuffer.cpp \
+    MtpUtils.cpp \
+    mtp_MtpServer.cpp \
+    twrpMtp.cpp \
+    mtp_MtpDatabase.cpp \
+    node.cpp
+LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils
+include $(BUILD_SHARED_LIBRARY)
+
+# Build twrpmtp binary / executable
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := twrpmtp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DMTP_DEVICE -DMTP_HOST -DTWRPMTP
+LOCAL_C_INCLUDES += $(LOCAL_PATH) bionic external/stlport/stlport frameworks/base/include system/core/include bionic/libc/private/
+LOCAL_SRC_FILES = \
+    btree.cpp \
+    MtpDataPacket.cpp \
+    MtpDebug.cpp \
+    MtpDevice.cpp \
+    MtpDeviceInfo.cpp \
+    MtpEventPacket.cpp \
+    MtpObjectInfo.cpp \
+    MtpPacket.cpp \
+    MtpProperty.cpp \
+    MtpRequestPacket.cpp \
+    MtpResponsePacket.cpp \
+    MtpServer.cpp \
+    MtpStorage.cpp \
+    MtpStorageInfo.cpp \
+    MtpStringBuffer.cpp \
+    MtpUtils.cpp \
+    mtp_MtpServer.cpp \
+    twrpMtp.cpp \
+    mtp_MtpDatabase.cpp \
+    node.cpp
+LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils
+include $(BUILD_EXECUTABLE)
diff --git a/mtp/MtpDataPacket.cpp b/mtp/MtpDataPacket.cpp
new file mode 100755
index 0000000..2c51725
--- /dev/null
+++ b/mtp/MtpDataPacket.cpp
@@ -0,0 +1,488 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to c++
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <usbhost/usbhost.h>
+
+#include "MtpDataPacket.h"
+#include "MtpStringBuffer.h"
+#include "MtpDebug.h"
+
+#define MTP_BUFFER_SIZE 16384
+
+
+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(getInt8());
+	return result;
+}
+
+UInt8List* MtpDataPacket::getAUInt8() {
+	UInt8List* result = new UInt8List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getUInt8());
+	return result;
+}
+
+Int16List* MtpDataPacket::getAInt16() {
+	Int16List* result = new Int16List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getInt16());
+	return result;
+}
+
+UInt16List* MtpDataPacket::getAUInt16() {
+	UInt16List* result = new UInt16List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getUInt16());
+	return result;
+}
+
+Int32List* MtpDataPacket::getAInt32() {
+	Int32List* result = new Int32List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getInt32());
+	return result;
+}
+
+UInt32List* MtpDataPacket::getAUInt32() {
+	UInt32List* result = new UInt32List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getUInt32());
+	return result;
+}
+
+Int64List* MtpDataPacket::getAInt64() {
+	Int64List* result = new Int64List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(getInt64());
+	return result;
+}
+
+UInt64List* MtpDataPacket::getAUInt64() {
+	UInt64List* result = new UInt64List;
+	int count = getUInt32();
+	for (int i = 0; i < count; i++)
+		result->push(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;
+	int32_t 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 > (uint32_t)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)) {
+		MTPE("usb_endpoint_queue failed, errno: %d", errno);
+		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;
+}
+
diff --git a/mtp/MtpDataPacket.h b/mtp/MtpDataPacket.h
new file mode 100755
index 0000000..0e7a873
--- /dev/null
+++ b/mtp/MtpDataPacket.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to c++
+ *
+ */
+
+#ifndef _MTP_DATA_PACKET_H
+#define _MTP_DATA_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+struct usb_device;
+struct usb_request;
+
+
+class MtpStringBuffer;
+
+class MtpDataPacket : public MtpPacket {
+private:
+    // current offset for get/put methods
+    uint64_t            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;
+};
+
+
+#endif // _MTP_DATA_PACKET_H
diff --git a/mtp/MtpDatabase.h b/mtp/MtpDatabase.h
new file mode 100755
index 0000000..c25e9b2
--- /dev/null
+++ b/mtp/MtpDatabase.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to c++
+ */
+
+#ifndef _MTP_DATABASE_H
+#define _MTP_DATABASE_H
+
+#include "MtpTypes.h"
+
+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 char* 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 char* 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 void 					createDB(MtpStorage* storage, MtpStorageID storageID) = 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 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() = 0;
+
+    virtual void                    sessionEnded() = 0;
+    virtual void                    lockMutex() = 0;
+    virtual void                    unlockMutex() = 0;
+};
+
+#endif // _MTP_DATABASE_H
diff --git a/mtp/MtpDebug.cpp b/mtp/MtpDebug.cpp
new file mode 100755
index 0000000..c3a3d8a
--- /dev/null
+++ b/mtp/MtpDebug.cpp
@@ -0,0 +1,419 @@
+/*
+ * 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.
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ */
+
+#include "MtpDebug.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+#define MTP_DEBUG_BUFFER_SIZE 2048
+//#define MTP_DEBUG 1
+
+extern "C" void mtpdebug(const char *fmt, ...)
+{
+#ifdef MTP_DEBUG
+	char buf[MTP_DEBUG_BUFFER_SIZE];		// We're going to limit a single request to 512 bytes
+
+	va_list ap;
+	va_start(ap, fmt);
+	vsnprintf(buf, MTP_DEBUG_BUFFER_SIZE, fmt, ap);
+	va_end(ap);
+
+	fputs(buf, stdout);
+#endif
+}
+
+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);
+}
diff --git a/mtp/MtpDebug.h b/mtp/MtpDebug.h
new file mode 100755
index 0000000..12a23cc
--- /dev/null
+++ b/mtp/MtpDebug.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_DEBUG_H
+#define _MTP_DEBUG_H
+
+// #define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "MtpTypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void mtpdebug(const char *fmt, ...);
+
+#define MTPI(...) fprintf(stdout, __VA_ARGS__)
+#define MTPD(...) mtpdebug(__VA_ARGS__)
+#define MTPE(...) fprintf(stdout, "E:" __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+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);
+};
+
+
+#endif // _MTP_DEBUG_H
diff --git a/mtp/MtpDevice.cpp b/mtp/MtpDevice.cpp
new file mode 100755
index 0000000..53f8b2e
--- /dev/null
+++ b/mtp/MtpDevice.cpp
@@ -0,0 +1,833 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDevice.h"
+#include "MtpDebug.h"
+#include "MtpDeviceInfo.h"
+#include "MtpObjectInfo.h"
+#include "MtpProperty.h"
+#include "MtpStorageInfo.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+#include "MtpDataPacket.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <endian.h>
+
+#include <usbhost/usbhost.h>
+
+
+#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) {
+		MTPE("usb_device_new failed for %s", 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);
+				MTPD("Found camera: \"%s\" \"%s\"\n", 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);
+				MTPI("Found MTP device: \"%s\" \"%s\"\n", 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);
+				MTPE("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
+				if (ret > 0) {
+					MTPI("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);
+					MTPI("OS descriptor got %d\n", ret);
+				} else {
+					MTPI("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) {
+					MTPE("endpoints not found\n");
+					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) {
+				MTPE("endpoints not found\n");
+				usb_device_close(device);
+				return NULL;
+			}
+
+			if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+				MTPE("usb_device_claim_interface failed errno: %d\n", errno);
+				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);
+	MTPE("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 (size_t 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(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) {
+			MTPI("***** DEVICE PROPERTIES *****\n");
+			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) {
+			MTPI("***** OBJECT PROPERTIES *****\n");
+		int count = mDeviceInfo->mPlaybackFormats->size();
+		for (int i = 0; i < count; i++) {
+			MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
+			MTPI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
+			MtpObjectPropertyList* props = getObjectPropsSupported(format);
+			if (props) {
+				for (size_t j = 0; j < props->size(); j++) {
+					MtpObjectProperty prop = (*props)[j];
+					MtpProperty* property = getObjectPropDesc(prop, format);
+					if (property) {
+						property->print();
+						delete property;
+					} else {
+						MTPI("could not fetch property: %s",
+								MtpDebug::getObjectPropCodeName(prop));
+					}
+				}
+			}
+		}
+	}
+}
+
+const char* MtpDevice::getDeviceName() {
+	if (mDevice)
+		return usb_device_get_name(mDevice);
+	else
+		return "???";
+}
+
+bool MtpDevice::openSession() {
+	android::Mutex::Autolock 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() {
+	android::Mutex::Autolock 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() {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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) {
+	android::Mutex::Autolock 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 ((int)length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
+			MTPE("readObject error objectSize: %d, length: %d",
+					objectSize, 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)) {
+					MTPE("readDataAsync failed");
+					goto fail;
+				}
+			} else {
+				req = NULL;
+			}
+
+			if (writeBuffer) {
+				// write previous buffer
+				if (!callback(writeBuffer, offset, writeLength, clientData)) {
+					MTPE("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) {
+	MTPI("readObject: %s", destPath);
+	int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, 0640);
+	if (fd < 0) {
+		MTPE("open failed for %s", destPath);
+		return false;
+	}
+
+	fchown(fd, getuid(), group);
+	// set permissions
+	int mask = umask(0);
+	fchmod(fd, perm);
+	umask(mask);
+
+	android::Mutex::Autolock 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)) {
+					MTPE("readDataAsync failed");
+					goto fail;
+				}
+			} else {
+				req = NULL;
+			}
+
+			if (writeBuffer) {
+				// write previous buffer
+				if (write(fd, writeBuffer, writeLength) != writeLength) {
+					MTPE("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) {
+	MTPD("sendRequest: %s\n", 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() {
+	MTPD("sendData\n");
+	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);
+	MTPD("readData returned %d\n", ret);
+	if (ret >= MTP_CONTAINER_HEADER_SIZE) {
+		if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+			MTPD("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 {
+		MTPE("readResponse failed\n");
+		return false;
+	}
+}
+
+bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
+	mData.setOperationCode(operation);
+	mData.setTransactionID(mRequest.getTransactionID());
+	return (!mData.writeDataHeader(mRequestOut, dataLength));
+}
+
+MtpResponseCode MtpDevice::readResponse() {
+	MTPD("readResponse\n");
+	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 {
+		MTPE("readResponse failed\n");
+		return -1;
+	}
+}
diff --git a/mtp/MtpDevice.h b/mtp/MtpDevice.h
new file mode 100755
index 0000000..d90b0c0
--- /dev/null
+++ b/mtp/MtpDevice.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_DEVICE_H
+#define _MTP_DEVICE_H
+
+#include "MtpRequestPacket.h"
+#include "MtpDataPacket.h"
+#include "MtpResponsePacket.h"
+#include "MtpTypes.h"
+
+#include <utils/threads.h>
+
+struct usb_device;
+struct usb_request;
+struct usb_endpoint_descriptor;
+
+
+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
+    android::Mutex                   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();
+
+};
+
+
+#endif // _MTP_DEVICE_H
diff --git a/mtp/MtpDeviceInfo.cpp b/mtp/MtpDeviceInfo.cpp
new file mode 100755
index 0000000..337cc13
--- /dev/null
+++ b/mtp/MtpDeviceInfo.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDebug.h"
+#include "MtpDataPacket.h"
+#include "MtpDeviceInfo.h"
+#include "MtpStringBuffer.h"
+
+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() {
+	MTPI("Device Info:\n\tmStandardVersion: %d\n\tmVendorExtensionID: %d\n\tmVendorExtensionVersiony: %d\n",
+			mStandardVersion, mVendorExtensionID, mVendorExtensionVersion);
+	MTPI("\tmVendorExtensionDesc: %s\n\tmFunctionalCode: %d\n\tmManufacturer: %s\n\tmModel: %s\n\tmVersion: %s\n\tmSerial: %s\n",
+			mVendorExtensionDesc, mFunctionalCode, mManufacturer, mModel, mVersion, mSerial);
+}
+
diff --git a/mtp/MtpDeviceInfo.h b/mtp/MtpDeviceInfo.h
new file mode 100755
index 0000000..b316371
--- /dev/null
+++ b/mtp/MtpDeviceInfo.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_DEVICE_INFO_H
+#define _MTP_DEVICE_INFO_H
+
+struct stat;
+
+
+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();
+};
+
+
+#endif // _MTP_DEVICE_INFO_H
diff --git a/mtp/MtpEventPacket.cpp b/mtp/MtpEventPacket.cpp
new file mode 100755
index 0000000..1119f7d
--- /dev/null
+++ b/mtp/MtpEventPacket.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#ifdef MTP_DEVICE
+#include <linux/usb/f_mtp.h>
+#endif
+
+#include "MtpEventPacket.h"
+
+#include <usbhost/usbhost.h>
+
+
+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
+
+
diff --git a/mtp/MtpEventPacket.h b/mtp/MtpEventPacket.h
new file mode 100755
index 0000000..b42abce
--- /dev/null
+++ b/mtp/MtpEventPacket.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_EVENT_PACKET_H
+#define _MTP_EVENT_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+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); }
+};
+
+#endif // _MTP_EVENT_PACKET_H
diff --git a/mtp/MtpObjectInfo.cpp b/mtp/MtpObjectInfo.cpp
new file mode 100755
index 0000000..50192d7
--- /dev/null
+++ b/mtp/MtpObjectInfo.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDebug.h"
+#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+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() {
+	MTPI("MtpObject Info %08X: %s\n", mHandle, mName);
+	MTPI("  mStorageID: %08X mFormat: %04X mProtectionStatus: %d\n",
+			mStorageID, mFormat, mProtectionStatus);
+	MTPI("  mCompressedSize: %d mThumbFormat: %04X mThumbCompressedSize: %d\n",
+			mCompressedSize, mFormat, mThumbCompressedSize);
+	MTPI("  mThumbPixWidth: %d mThumbPixHeight: %d\n", mThumbPixWidth, mThumbPixHeight);
+	MTPI("  mImagePixWidth: %d mImagePixHeight: %d mImagePixDepth: %d\n",
+			mImagePixWidth, mImagePixHeight, mImagePixDepth);
+	MTPI("  mParent: %08X mAssociationType: %04X mAssociationDesc: %04X\n",
+			mParent, mAssociationType, mAssociationDesc);
+	MTPI("  mSequenceNumber: %d mDateCreated: %ld mDateModified: %ld mKeywords: %s\n",
+			mSequenceNumber, mDateCreated, mDateModified, mKeywords);
+}
+
diff --git a/mtp/MtpObjectInfo.h b/mtp/MtpObjectInfo.h
new file mode 100755
index 0000000..406c3f4
--- /dev/null
+++ b/mtp/MtpObjectInfo.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_OBJECT_INFO_H
+#define _MTP_OBJECT_INFO_H
+
+#include "MtpTypes.h"
+
+
+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();
+};
+
+
+#endif // _MTP_OBJECT_INFO_H
diff --git a/mtp/MtpPacket.cpp b/mtp/MtpPacket.cpp
new file mode 100755
index 0000000..2f9e438
--- /dev/null
+++ b/mtp/MtpPacket.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDebug.h"
+#include "MtpPacket.h"
+#include "mtp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <usbhost/usbhost.h>
+
+
+MtpPacket::MtpPacket(int bufferSize)
+	:   mBuffer(NULL),
+		mBufferSize(bufferSize),
+		mAllocationIncrement(bufferSize),
+		mPacketSize(0)
+{
+	mBuffer = (uint8_t *)malloc(bufferSize);
+	if (!mBuffer) {
+		MTPE("out of memory!");
+		abort();
+	}
+}
+
+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) {
+			MTPE("out of memory!");
+			abort();
+		}
+		mBufferSize = newLength;
+	}
+}
+
+void MtpPacket::dump() {
+#define DUMP_BYTES_PER_ROW  16
+	char buffer[500];
+	char* bufptr = buffer;
+
+	for (size_t i = 0; i < mPacketSize; i++) {
+		sprintf(bufptr, "%02X ", mBuffer[i]);
+		bufptr += strlen(bufptr);
+		if (i % DUMP_BYTES_PER_ROW == (DUMP_BYTES_PER_ROW - 1)) {
+			MTPD("%s", buffer);
+			bufptr = buffer;
+		}
+	}
+	if (bufptr != buffer) {
+		// print last line
+		MTPD("%s", buffer);
+	}
+	MTPD("\n");
+}
+
+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) {
+		MTPE("index %d out of range in MtpPacket::getParameter", index);
+		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) {
+		MTPE("index %d out of range in MtpPacket::setParameter", index);
+		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
+
diff --git a/mtp/MtpPacket.h b/mtp/MtpPacket.h
new file mode 100755
index 0000000..ec763c8
--- /dev/null
+++ b/mtp/MtpPacket.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_PACKET_H
+#define _MTP_PACKET_H
+
+#include "MtpTypes.h"
+
+struct usb_request;
+
+
+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
+    unsigned            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);
+};
+
+
+#endif // _MTP_PACKET_H
diff --git a/mtp/MtpProperty.cpp b/mtp/MtpProperty.cpp
new file mode 100755
index 0000000..e105f24
--- /dev/null
+++ b/mtp/MtpProperty.cpp
@@ -0,0 +1,531 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDataPacket.h"
+#include "MtpDebug.h"
+#include "MtpProperty.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+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:
+				MTPE("unknown type %04X in MtpProperty::MtpProperty", type);
+		}
+	}
+}
+
+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:
+			MTPE("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:
+					MTPE("unsupported type for MtpProperty::setEnum");
+					break;
+		}
+	}
+}
+
+void MtpProperty::setFormDateTime() {
+	 mFormFlag = kFormDateTime;
+}
+
+void MtpProperty::print() {
+	MtpString buffer;
+	bool deviceProp = isDeviceProperty();
+	if (deviceProp)
+		MTPI("	%s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode);
+	else
+		MTPI("	%s (%04X)", MtpDebug::getObjectPropCodeName(mCode), mCode);
+	MTPI("	type %04X", mType);
+	MTPI("	writeable %s", (mWriteable ? "true" : "false"));
+	buffer = "	default value: ";
+	print(mDefaultValue, buffer);
+	MTPI("%s", (const char *)buffer);
+	if (deviceProp) {
+		buffer = "	current value: ";
+		print(mCurrentValue, buffer);
+		MTPI("%s", (const char *)buffer);
+	}
+	switch (mFormFlag) {
+		case kFormNone:
+			break;
+		case kFormRange:
+			buffer = "	Range (";
+			print(mMinimumValue, buffer);
+			buffer += ", ";
+			print(mMaximumValue, buffer);
+			buffer += ", ";
+			print(mStepSize, buffer);
+			buffer += ")";
+			MTPI("%s", (const char *)buffer);
+			break;
+		case kFormEnum:
+			buffer = "	Enum { ";
+			for (int i = 0; i < mEnumLength; i++) {
+				print(mEnumValues[i], buffer);
+				buffer += " ";
+			}
+			buffer += "}";
+			MTPI("%s", (const char *)buffer);
+			break;
+		case kFormDateTime:
+			MTPI("	DateTime\n");
+			break;
+		default:
+			MTPI("	form %d\n", mFormFlag);
+			break;
+	}
+}
+
+void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) {
+	switch (mType) {
+		case MTP_TYPE_INT8:
+			buffer.appendFormat("%d", value.u.i8);
+			break;
+		case MTP_TYPE_UINT8:
+			buffer.appendFormat("%d", value.u.u8);
+			break;
+		case MTP_TYPE_INT16:
+			buffer.appendFormat("%d", value.u.i16);
+			break;
+		case MTP_TYPE_UINT16:
+			buffer.appendFormat("%d", value.u.u16);
+			break;
+		case MTP_TYPE_INT32:
+			buffer.appendFormat("%d", value.u.i32);
+			break;
+		case MTP_TYPE_UINT32:
+			buffer.appendFormat("%d", value.u.u32);
+			break;
+		case MTP_TYPE_INT64:
+			buffer.appendFormat("%lld", value.u.i64);
+			break;
+		case MTP_TYPE_UINT64:
+			buffer.appendFormat("%lld", value.u.u64);
+			break;
+		case MTP_TYPE_INT128:
+			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:
+			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:
+			buffer.appendFormat("%s", value.str);
+			break;
+		default:
+			MTPE("unsupported type for MtpProperty::print\n");
+			break;
+	}
+}
+
+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:
+			MTPE("unknown type %04X in MtpProperty::readValue", mType);
+	}
+}
+
+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:
+			MTPE("unknown type %04X in MtpProperty::writeValue", mType);
+	}
+}
+
+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]);
+}
+
diff --git a/mtp/MtpProperty.h b/mtp/MtpProperty.h
new file mode 100755
index 0000000..017d875
--- /dev/null
+++ b/mtp/MtpProperty.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_PROPERTY_H
+#define _MTP_PROPERTY_H
+
+#include "MtpTypes.h"
+
+
+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);
+};
+
+
+#endif // _MTP_PROPERTY_H
diff --git a/mtp/MtpRequestPacket.cpp b/mtp/MtpRequestPacket.cpp
new file mode 100755
index 0000000..754e205
--- /dev/null
+++ b/mtp/MtpRequestPacket.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "MtpRequestPacket.h"
+#include "MtpDebug.h"
+
+#include <usbhost/usbhost.h>
+
+
+MtpRequestPacket::MtpRequestPacket()
+	:	MtpPacket(512)
+{
+}
+
+MtpRequestPacket::~MtpRequestPacket() {
+}
+
+#ifdef MTP_DEVICE
+int MtpRequestPacket::read(int fd) {
+	MTPD("block1 fd: %d\n", fd);
+	int ret = ::read(fd, mBuffer, mBufferSize);
+	MTPD("block2\n");
+	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
+
diff --git a/mtp/MtpRequestPacket.h b/mtp/MtpRequestPacket.h
new file mode 100755
index 0000000..8551dde
--- /dev/null
+++ b/mtp/MtpRequestPacket.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_REQUEST_PACKET_H
+#define _MTP_REQUEST_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+struct usb_request;
+
+
+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); }
+};
+
+
+#endif // _MTP_REQUEST_PACKET_H
diff --git a/mtp/MtpResponsePacket.cpp b/mtp/MtpResponsePacket.cpp
new file mode 100755
index 0000000..8eed13a
--- /dev/null
+++ b/mtp/MtpResponsePacket.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use 	 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "MtpResponsePacket.h"
+
+#include <usbhost/usbhost.h>
+
+
+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
+
+
diff --git a/mtp/MtpResponsePacket.h b/mtp/MtpResponsePacket.h
new file mode 100755
index 0000000..749b534
--- /dev/null
+++ b/mtp/MtpResponsePacket.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_RESPONSE_PACKET_H
+#define _MTP_RESPONSE_PACKET_H
+
+#include "MtpPacket.h"
+#include "mtp.h"
+
+
+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); }
+};
+
+
+#endif // _MTP_RESPONSE_PACKET_H
diff --git a/mtp/MtpServer.cpp b/mtp/MtpServer.cpp
new file mode 100755
index 0000000..5dec580
--- /dev/null
+++ b/mtp/MtpServer.cpp
@@ -0,0 +1,1337 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include "../twcommon.h"
+#include <cutils/properties.h>
+
+#include "MtpTypes.h"
+#include "MtpDebug.h"
+#include "MtpDatabase.h"
+#include "MtpObjectInfo.h"
+#include "MtpProperty.h"
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "MtpStringBuffer.h"
+
+#include <linux/usb/f_mtp.h>
+
+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_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) {
+	MTPD("addStorage(): storage: %x\n", storage);
+	mDatabase->createDB(storage, storage->getStorageID());
+	android::Mutex::Autolock autoLock(mMutex);
+	mStorages.push(storage);
+	sendStoreAdded(storage->getStorageID());
+}
+
+void MtpServer::removeStorage(MtpStorage* storage) {
+	android::Mutex::Autolock autoLock(mMutex);
+
+	for (size_t i = 0; i < mStorages.size(); i++) {
+		if (mStorages[i] == storage) {
+			mStorages.removeAt(i);
+			sendStoreRemoved(storage->getStorageID());
+			break;
+		}
+	}
+}
+
+MtpStorage* MtpServer::getStorage(MtpStorageID id) {
+	MTPD("getStorage\n");
+	if (id == 0) {
+		MTPD("mStorages\n");
+		return mStorages[0];
+	}
+	for (size_t i = 0; i < mStorages.size(); i++) {
+		MtpStorage* storage = mStorages[i];
+		MTPD("id: %d\n", id);
+		MTPD("storage: %d\n", storage->getStorageID());
+		if (storage->getStorageID() == id) {
+			return storage;
+		}
+	}
+	return NULL;
+}
+
+bool MtpServer::hasStorage(MtpStorageID id) {
+	MTPD("in hasStorage\n");
+	if (id == 0 || id == 0xFFFFFFFF)
+		return mStorages.size() > 0;
+	return (getStorage(id) != NULL);
+}
+
+void MtpServer::run() {
+	int fd = mFD;
+
+	MTPI("MtpServer::run fd: %d\n", fd);
+
+	while (1) {
+		MTPD("About to read device...\n");
+		int ret = mRequest.read(fd);
+		if (ret < 0) {
+			MTPD("request read returned %d, errno: %d", ret, errno);
+			if (errno == ECANCELED) {
+				// return to top of loop and wait for next command
+				continue;
+			}
+			break;
+		}
+		MtpOperationCode operation = mRequest.getOperationCode();
+		MtpTransactionID transaction = mRequest.getTransactionID();
+
+		MTPD("operation: %s", 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) {
+				MTPD("data read returned %d, errno: %d", ret, errno);
+				if (errno == ECANCELED) {
+					// return to top of loop and wait for next command
+					continue;
+				}
+				break;
+			}
+			MTPD("received data:");
+			mData.dump();
+		} else {
+			mData.reset();
+		}
+
+		if (handleRequest()) {
+			if (!dataIn && mData.hasData()) {
+				mData.setOperationCode(operation);
+				mData.setTransactionID(transaction);
+				MTPD("sending data:");
+				mData.dump();
+				ret = mData.write(fd);
+				if (ret < 0) {
+					MTPD("request write returned %d, errno: %d", ret, errno);
+					if (errno == ECANCELED) {
+						// return to top of loop and wait for next command
+						continue;
+					}
+					break;
+				}
+			}
+
+			mResponse.setTransactionID(transaction);
+			MTPD("sending response %04X\n", mResponse.getResponseCode());
+			ret = mResponse.write(fd);
+			MTPD("ret: %d\n", ret);
+			mResponse.dump();
+			if (ret < 0) {
+				MTPD("request write returned %d, errno: %d", ret, errno);
+				if (errno == ECANCELED) {
+					// return to top of loop and wait for next command
+					continue;
+				}
+				break;
+			}
+		} else {
+			MTPD("skipping response\n");
+		}
+	}
+
+	// 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) {
+	MTPD("sendObjectAdded %d\n", handle);
+	sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
+}
+
+void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
+	MTPD("sendObjectRemoved %d\n", handle);
+	sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
+}
+
+void MtpServer::sendObjectUpdated(MtpObjectHandle handle) {
+	MTPD("sendObjectUpdated %d\n", handle);
+	sendEvent(MTP_EVENT_OBJECT_PROP_CHANGED, handle);
+}
+
+void MtpServer::sendStoreAdded(MtpStorageID id) {
+	MTPD("sendStoreAdded %08X\n", id);
+	sendEvent(MTP_EVENT_STORE_ADDED, id);
+}
+
+void MtpServer::sendStoreRemoved(MtpStorageID id) {
+	MTPD("sendStoreRemoved %08X\n", id);
+	sendEvent(MTP_EVENT_STORE_REMOVED, id);
+}
+
+void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
+	MTPD("MtpServer::sendEvent sending event code: %x\n", code);
+	if (mSessionOpen) {
+		mEvent.setEventCode(code);
+		mEvent.setTransactionID(mRequest.getTransactionID());
+		mEvent.setParameter(1, param1);
+		int ret = mEvent.write(mFD);
+		MTPD("mEvent.write returned %d\n", 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.add(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.removeAt(i);
+			return;
+		}
+	}
+	MTPE("ObjectEdit not found in removeEditObject");
+}
+
+void MtpServer::commitEdit(ObjectEdit* edit) {
+	mDatabase->endSendObject((const char *)edit->mPath, edit->mHandle, edit->mFormat, true);
+}
+
+
+bool MtpServer::handleRequest() {
+	android::Mutex::Autolock 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
+		MTPE("expected SendObject after SendObjectInfo");
+		mSendObjectHandle = kInvalidObjectHandle;
+	}
+
+	switch (operation) {
+		case MTP_OPERATION_GET_DEVICE_INFO:
+				MTPD("doGetDeviceInfo()\n");
+				response = doGetDeviceInfo();
+				break;
+			case MTP_OPERATION_OPEN_SESSION:
+				MTPD("doOpenSesion()\n");
+				response = doOpenSession();
+				break;
+			case MTP_OPERATION_CLOSE_SESSION:
+				MTPD("doCloseSession()\n");
+				response = doCloseSession();
+				break;
+			case MTP_OPERATION_GET_STORAGE_IDS:
+				MTPD("doGetStorageIDs()\n");
+				response = doGetStorageIDs();
+				break;
+		 	 case MTP_OPERATION_GET_STORAGE_INFO:
+				MTPD("about to call doGetStorageInfo()\n");
+				response = doGetStorageInfo();
+				break;
+			case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
+				MTPD("about to call doGetObjectPropsSupported()\n");
+				response = doGetObjectPropsSupported();
+				break;
+			case MTP_OPERATION_GET_OBJECT_HANDLES:
+				MTPD("about to call doGetObjectHandles()\n");
+				response = doGetObjectHandles();
+				break;
+			case MTP_OPERATION_GET_NUM_OBJECTS:
+				MTPD("about to call doGetNumbObjects()\n");
+				response = doGetNumObjects();
+				break;
+			case MTP_OPERATION_GET_OBJECT_REFERENCES:
+				MTPD("about to call doGetObjectReferences()\n");
+				response = doGetObjectReferences();
+				break;
+			case MTP_OPERATION_SET_OBJECT_REFERENCES:
+				MTPD("about to call doSetObjectReferences()\n");
+				response = doSetObjectReferences();
+				break;
+			case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
+				MTPD("about to call doGetObjectPropValue()\n");
+				response = doGetObjectPropValue();
+				break;
+			case MTP_OPERATION_SET_OBJECT_PROP_VALUE:
+				MTPD("about to call doSetObjectPropValue()\n");
+				response = doSetObjectPropValue();
+				break;
+			case MTP_OPERATION_GET_DEVICE_PROP_VALUE:
+				MTPD("about to call doGetDevicPropValue()\n");
+				response = doGetDevicePropValue();
+				break;
+			case MTP_OPERATION_SET_DEVICE_PROP_VALUE:
+				MTPD("about to call doSetDevicePropVaue()\n");
+				response = doSetDevicePropValue();
+				break;
+			case MTP_OPERATION_RESET_DEVICE_PROP_VALUE:
+				MTPD("about to call doResetDevicePropValue()\n");
+				response = doResetDevicePropValue();
+				break;
+			case MTP_OPERATION_GET_OBJECT_PROP_LIST:
+				MTPD("calling doGetObjectPropList()\n");
+				response = doGetObjectPropList();
+				break;
+			case MTP_OPERATION_GET_OBJECT_INFO:
+				MTPD("calling doGetObjectInfo()\n");
+				response = doGetObjectInfo();
+				break;
+			case MTP_OPERATION_GET_OBJECT:
+				MTPD("about to call doGetObject()\n");
+				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:
+				MTPD("about to call doSendObjectInfo()\n");
+				response = doSendObjectInfo();
+				break;
+			case MTP_OPERATION_SEND_OBJECT:
+				MTPD("about to call doSendObject()\n");
+				response = doSendObject();
+				break;
+			case MTP_OPERATION_DELETE_OBJECT:
+				response = doDeleteObject();
+				break;
+			case MTP_OPERATION_GET_OBJECT_PROP_DESC:
+				MTPD("about to call doGetObjectPropDesc()\n");
+				response = doGetObjectPropDesc();
+				break;
+			case MTP_OPERATION_GET_DEVICE_PROP_DESC:
+				MTPD("about to call doGetDevicePropDesc()\n");
+				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:
+				MTPE("got unsupported command %s", 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() {
+	MtpStringBuffer   string;
+	char prop_value[PROPERTY_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) {
+		MTPD("doGetDeviceInfo putting 0\n");
+		mData.putUInt32(0);
+	} else {
+		// MTP Vendor Extension ID
+		MTPD("doGetDeviceInfo putting 6\n");
+		mData.putUInt32(6);
+	}
+	mData.putUInt16(MTP_STANDARD_VERSION);
+	if (mPtp) {
+		// no extensions
+		MTPD("doGetDeviceInfo no extensions\n");
+		string.set("");
+	} else {
+		// MTP extensions
+		MTPD("doGetDeviceInfo microsoft.com: 1.0; android.com: 1.0;\n");
+		string.set("microsoft.com: 1.0; android.com: 1.0;");
+	}
+	mData.putString(string); // MTP Extensions
+	mData.putUInt16(0); //Functional Mode
+	MTPD("doGetDeviceInfo opcodes, %i\n", sizeof(kSupportedOperationCodes) / sizeof(uint16_t));
+	MTPD("doGetDeviceInfo eventcodes, %i\n", sizeof(kSupportedEventCodes) / sizeof(uint16_t));
+	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");
+	MTPD("prop: %s\n", prop_value);
+	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, "????????");
+	MTPD("sn: %s\n", 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();
+
+	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() {
+	MTPD("doGetStorageIDs()\n");
+	if (!mSessionOpen)
+		return MTP_RESPONSE_SESSION_NOT_OPEN;
+	int count = mStorages.size();
+	mData.putUInt32(count);
+	for (int i = 0; i < count; i++) {
+		MTPD("getting storageid %d\n", mStorages[i]->getStorageID());
+		mData.putUInt32(mStorages[i]->getStorageID());
+	}
+
+	return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetStorageInfo() {
+	MtpStringBuffer   string;
+	MTPD("doGetStorageInfo()\n");
+	if (!mSessionOpen)
+		return MTP_RESPONSE_SESSION_NOT_OPEN;
+	MtpStorageID id = mRequest.getParameter(1);
+	MtpStorage* storage = getStorage(id);
+	if (!storage) {
+		MTPE("invalid storage id\n");
+		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() {
+	MTPD("doGetObjectPropsSupported()\n");
+	if (!mSessionOpen)
+		return MTP_RESPONSE_SESSION_NOT_OPEN;
+	MtpObjectFormat format = mRequest.getParameter(1);
+	mDatabase->lockMutex();
+	MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
+	mData.putAUInt16(properties);
+	delete properties;
+	mDatabase->unlockMutex();
+	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;
+
+	MTPD("calling MtpDatabase->getObjectList()\n");
+	mDatabase->lockMutex();
+	MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
+	mData.putAUInt32(handles);
+	delete handles;
+	mDatabase->unlockMutex();
+	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;
+
+	mDatabase->lockMutex();
+	int count = mDatabase->getNumObjects(storageID, format, parent);
+	mDatabase->unlockMutex();
+	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
+	mDatabase->lockMutex();
+	MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
+	if (handles) {
+		mData.putAUInt32(handles);
+		delete handles;
+	} else {
+		MTPD("MtpServer::doGetObjectReferences putEmptyArray\n");
+		mData.putEmptyArray();
+	}
+	mDatabase->unlockMutex();
+	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();
+	mDatabase->lockMutex();
+	MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
+	mDatabase->unlockMutex();
+	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);
+	MTPD("GetObjectPropValue %d %s\n", handle,
+			MtpDebug::getObjectPropCodeName(property));
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->getObjectPropertyValue(handle, property, mData);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+MtpResponseCode MtpServer::doSetObjectPropValue() {
+	if (!hasStorage())
+		return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+	MtpObjectHandle handle = mRequest.getParameter(1);
+	MtpObjectProperty property = mRequest.getParameter(2);
+	MTPD("SetObjectPropValue %d %s\n", handle,
+			MtpDebug::getObjectPropCodeName(property));
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->setObjectPropertyValue(handle, property, mData);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+MtpResponseCode MtpServer::doGetDevicePropValue() {
+	MtpDeviceProperty property = mRequest.getParameter(1);
+	MTPD("GetDevicePropValue %s\n",
+			MtpDebug::getDevicePropCodeName(property));
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->getDevicePropertyValue(property, mData);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+MtpResponseCode MtpServer::doSetDevicePropValue() {
+	MtpDeviceProperty property = mRequest.getParameter(1);
+	MTPD("SetDevicePropValue %s\n",
+			MtpDebug::getDevicePropCodeName(property));
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->setDevicePropertyValue(property, mData);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+MtpResponseCode MtpServer::doResetDevicePropValue() {
+	MtpDeviceProperty property = mRequest.getParameter(1);
+	MTPD("ResetDevicePropValue %s\n",
+			MtpDebug::getDevicePropCodeName(property));
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->resetDeviceProperty(property);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+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);
+	MTPD("GetObjectPropList %d format: %s property: %x group: %d depth: %d\n",
+			handle, MtpDebug::getFormatCodeName(format),
+			property, groupCode, depth);
+
+	mDatabase->lockMutex();
+	MtpResponseCode res = mDatabase->getObjectPropertyList(handle, format, property, groupCode, depth, mData);
+	mDatabase->unlockMutex();
+	return res;
+}
+
+MtpResponseCode MtpServer::doGetObjectInfo() {
+	MTPD("inside doGetObjectInfo()\n");
+	if (!hasStorage())
+		return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+	MtpObjectHandle handle = mRequest.getParameter(1);
+	MtpObjectInfo info(handle);
+	MTPD("calling mtpdatabase getObjectInfo()\n");
+	mDatabase->lockMutex();
+	MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
+	mDatabase->unlockMutex();
+	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);
+		MTPD("info.mName: %s\n", info.mName);
+		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;
+	MTPD("MtpServer::doGetObject calling getObjectFilePath\n");
+	mDatabase->lockMutex();
+	int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
+	mDatabase->unlockMutex();
+	if (result != MTP_RESPONSE_OK)
+		return result;
+
+	const char* filePath = (const char *)pathBuf;
+	MTPD("filePath: %s\n", filePath);
+	mtp_file_range  mfr;
+	mfr.fd = open(filePath, O_RDONLY);
+	if (mfr.fd < 0) {
+		return MTP_RESPONSE_GENERAL_ERROR;
+	}
+	mfr.offset = 0;
+	mfr.length = fileLength;
+	MTPD("mfr.length: %lld\n", mfr.length);
+	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);
+	MTPD("MTP_SEND_FILE_WITH_HEADER returned %d\n", 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;
+	mDatabase->lockMutex();
+	void* thumb = mDatabase->getThumbnail(handle, thumbSize);
+	mDatabase->unlockMutex();
+	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;
+	MTPD("MtpServer::doGetPartialObject calling getObjectFilePath\n");
+	mDatabase->lockMutex();
+	int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
+	mDatabase->unlockMutex();
+	if (result != MTP_RESPONSE_OK) {
+		return result;
+	}
+	if (offset + length > (uint64_t)fileLength)
+		length = fileLength - offset;
+
+	const char* filePath = (const char *)pathBuf;
+	mtp_file_range  mfr;
+	mfr.fd = open(filePath, 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);
+	MTPD("MTP_SEND_FILE_WITH_HEADER returned %d\n", 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() {
+	MTPD("MtpServer::doSendObjectInfo starting\n");
+	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) {
+		MTPD("MtpServer::doSendObjectInfo special case root\n");
+		path = storage->getPath();
+		parent = 0;
+	} else {
+		int64_t length;
+		MtpObjectFormat format;
+		MTPD("MtpServer::doSendObjectInfo calling getObjectFilePath\n");
+		mDatabase->lockMutex();
+		int result = mDatabase->getObjectFilePath(parent, path, length, format);
+		mDatabase->unlockMutex();
+		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
+
+	MTPD("name: %s format: %04X\n", (const char *)name, format);
+	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;
+	}
+
+	MTPD("MtpServer::doSendObjectInfo path: %s parent: %d storageID: %08X\n", (const char*)path, parent, storageID);
+	mDatabase->lockMutex();
+	MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
+			format, parent, storageID, mSendObjectFileSize, modifiedTime);
+	mDatabase->unlockMutex();
+	if (handle == kInvalidObjectHandle) {
+		MTPE("MtpServer::doSendObjectInfo returning MTP_RESPONSE_GENERAL_ERROR, handle == kInvalidObjectHandle\n");
+		return MTP_RESPONSE_GENERAL_ERROR;
+	}
+
+  if (format == MTP_FORMAT_ASSOCIATION) {
+		mode_t mask = umask(0);
+		MTPD("MtpServer::doSendObjectInfo mkdir '%s'\n", (const char *)path);
+		int ret = mkdir((const char *)path, mDirectoryPermission);
+		umask(mask);
+		if (ret && ret != -EEXIST) {
+			MTPE("MtpServer::doSendObjectInfo returning MTP_RESPONSE_GENERAL_ERROR, ret && ret != -EEXIST\n");
+			return MTP_RESPONSE_GENERAL_ERROR;
+		}
+		chown((const char *)path, getuid(), mFileGroup);
+
+		// SendObject does not get sent for directories, so call endSendObject here instead
+		mDatabase->lockMutex();
+		mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
+		mDatabase->unlockMutex();
+	} 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);
+	MTPD("MtpServer::doSendObjectInfo returning MTP_RESPONSE_OK\n");
+	return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doSendObject() {
+	if (!hasStorage())
+		return MTP_RESPONSE_GENERAL_ERROR;
+	MtpResponseCode result = MTP_RESPONSE_OK;
+	mode_t mask;
+	int ret = 0, initialData;
+
+	if (mSendObjectHandle == kInvalidObjectHandle) {
+		MTPE("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) {
+		MTPE("MTP_RESPONSE_GENERAL_ERROR\n");
+		result = MTP_RESPONSE_GENERAL_ERROR;
+		goto done;
+	}
+	initialData = ret - MTP_CONTAINER_HEADER_SIZE;
+
+	mtp_file_range  mfr;
+	mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, 0640);
+	if (mfr.fd < 0) {
+		result = MTP_RESPONSE_GENERAL_ERROR;
+		MTPE("fd error\n");
+		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;
+		}
+
+		MTPD("receiving %s\n", (const char *)mSendObjectFilePath);
+		// transfer the file
+		ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+	}
+	close(mfr.fd);
+
+	if (ret < 0) {
+		unlink(mSendObjectFilePath);
+		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
+	MTPD("MTP_RECEIVE_FILE returned %d\n", ret);
+	mData.reset();
+	mDatabase->lockMutex();
+	mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
+			result == MTP_RESPONSE_OK);
+	mDatabase->unlockMutex();
+	mSendObjectHandle = kInvalidObjectHandle;
+	MTPD("result: %d\n", result);
+	mSendObjectFormat = 0;
+	return MTP_RESPONSE_OK;
+}
+
+static void deleteRecursive(const char* path) {
+	char pathbuf[PATH_MAX];
+	size_t pathLength = strlen(path);
+	if (pathLength >= sizeof(pathbuf) - 1) {
+		MTPE("path too long: %s\n", 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) {
+		MTPE("opendir %s failed: %s", path, strerror(errno));
+		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) {
+			MTPE("path %s/%s too long\n", path, name);
+			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 {
+		MTPE("deletePath stat failed for %s: %s", path, strerror(errno));
+	}
+}
+
+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;
+	MTPD("MtpServer::doDeleteObject calling getObjectFilePath\n");
+	mDatabase->lockMutex();
+	int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
+	if (result == MTP_RESPONSE_OK) {
+		MTPD("deleting %s", (const char *)filePath);
+		result = mDatabase->deleteFile(handle);
+		// Don't delete the actual files unless the database deletion is allowed
+		if (result == MTP_RESPONSE_OK) {
+			deletePath((const char *)filePath);
+		}
+	}
+	mDatabase->unlockMutex();
+	return result;
+}
+
+MtpResponseCode MtpServer::doGetObjectPropDesc() {
+	MtpObjectProperty propCode = mRequest.getParameter(1);
+	MtpObjectFormat format = mRequest.getParameter(2);
+	MTPD("MtpServer::doGetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
+										MtpDebug::getFormatCodeName(format));
+	mDatabase->lockMutex();
+	MtpProperty* property = mDatabase->getObjectPropertyDesc(propCode, format);
+	mDatabase->unlockMutex();
+	if (!property) {
+		MTPE("MtpServer::doGetObjectPropDesc propery not supported\n");
+		return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+	}
+	property->write(mData);
+	delete property;
+	return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpServer::doGetDevicePropDesc() {
+	MtpDeviceProperty propCode = mRequest.getParameter(1);
+	MTPD("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
+	mDatabase->lockMutex();
+	MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
+	mDatabase->unlockMutex();
+	if (!property) {
+		MTPE("MtpServer::doGetDevicePropDesc property not supported\n");
+		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) {
+		MTPE("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) {
+		MTPE("writing past end of object, offset: %lld, edit->mSize: %lld", offset, edit->mSize);
+		return MTP_RESPONSE_GENERAL_ERROR;
+	}
+
+	const char* filePath = (const char *)edit->mPath;
+	MTPD("receiving partial %s %lld %lld\n", 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);
+		MTPD("MTP_RECEIVE_FILE returned %d", 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) {
+		MTPE("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)) {
+		MTPE("object already open for edit in doBeginEditObject");
+		return MTP_RESPONSE_GENERAL_ERROR;
+	}
+
+	MtpString path;
+	int64_t fileLength;
+	MtpObjectFormat format;
+	MTPD("MtpServer::doBeginEditObject calling getObjectFilePath\n");
+	mDatabase->lockMutex();
+	int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
+	mDatabase->unlockMutex();
+	if (result != MTP_RESPONSE_OK)
+		return result;
+
+	int fd = open((const char *)path, O_RDWR | O_EXCL);
+	if (fd < 0) {
+		MTPE("open failed for %s in doBeginEditObject (%d)", (const char *)path, errno);
+		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) {
+		MTPE("object not open for edit in doEndEditObject");
+		return MTP_RESPONSE_GENERAL_ERROR;
+	}
+
+	commitEdit(edit);
+	removeEditObject(handle);
+	return MTP_RESPONSE_OK;
+}
diff --git a/mtp/MtpServer.h b/mtp/MtpServer.h
new file mode 100755
index 0000000..61f5ccf
--- /dev/null
+++ b/mtp/MtpServer.h
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_SERVER_H
+#define _MTP_SERVER_H
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include "MtpRequestPacket.h"
+#include "MtpDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpResponsePacket.h"
+#include "MtpEventPacket.h"
+#include "mtp.h"
+#include "MtpUtils.h"
+
+
+class MtpDatabase;
+class MtpStorage;
+
+class MtpServer {
+
+private:
+    // file descriptor for MTP kernel driver
+    int                 mFD;
+	android::Mutex                   mMutex;
+    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;
+
+	pthread_mutex_t mtpMutex;
+
+    // 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 char* path, uint64_t size,
+            MtpObjectFormat format, int fd)
+                : mHandle(handle), mPath(path), mSize(size), mFormat(format), mFD(fd) {
+            }
+
+        virtual ~ObjectEdit() {
+            close(mFD);
+        }
+    };
+    android::Vector<ObjectEdit*>  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                sendObjectUpdated(MtpObjectHandle handle);
+
+private:
+    void                sendStoreAdded(MtpStorageID id);
+    void                sendStoreRemoved(MtpStorageID id);
+    void                sendEvent(MtpEventCode code, uint32_t param1);
+
+    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     doGetObjectPropDesc();
+    MtpResponseCode     doGetDevicePropDesc();
+    MtpResponseCode     doSendPartialObject();
+    MtpResponseCode     doTruncateObject();
+    MtpResponseCode     doBeginEditObject();
+    MtpResponseCode     doEndEditObject();
+};
+
+#endif // _MTP_SERVER_H
diff --git a/mtp/MtpStorage.cpp b/mtp/MtpStorage.cpp
new file mode 100755
index 0000000..e20dab4
--- /dev/null
+++ b/mtp/MtpStorage.cpp
@@ -0,0 +1,941 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDebug.h"
+#include "MtpStorage.h"
+#include "MtpDataPacket.h"
+#include "MtpServer.h"
+#include "MtpEventPacket.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/inotify.h>
+#include <fcntl.h>
+#include <sstream>
+
+#define WATCH_FLAGS ( IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY )
+
+static int mtpid = 0;
+
+MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
+		const char* description, uint64_t reserveSpace,
+		bool removable, uint64_t maxFileSize, MtpServer* refserver)
+	:	mStorageID(id),
+		mFilePath(filePath),
+		mDescription(description),
+		mMaxCapacity(0),
+		mMaxFileSize(maxFileSize),
+		mReserveSpace(reserveSpace),
+		mRemovable(removable),
+		mServer(refserver)
+{
+	MTPI("MtpStorage id: %d path: %s\n", id, filePath);
+	mtpparentid = 0;
+	inotify_thread = 0;
+	sendEvents = false;
+	use_mutex = true;
+	if (pthread_mutex_init(&mtpMutex, NULL) != 0) {
+		MTPE("Failed to init mtpMutex\n");
+		use_mutex = false;
+	}
+	if (pthread_mutex_init(&inMutex, NULL) != 0) {
+		MTPE("Failed to init inMutex\n");
+		use_mutex = false;
+	}
+	
+}
+
+MtpStorage::~MtpStorage() {
+	if (inotify_thread) {
+		pthread_kill(inotify_thread, 0);
+		for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+			inotify_rm_watch(inotify_fd, i->first);
+		}
+		close(inotify_fd);
+	}
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+		delete i->second;
+	}
+	if (use_mutex) {
+		use_mutex = false;
+		pthread_mutex_destroy(&mtpMutex);
+		pthread_mutex_destroy(&inMutex);
+	}
+}
+
+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 (const char *)mDescription;
+}
+
+int MtpStorage::createDB() {
+	std::string mtpParent = "";
+	mtpstorageparent = getPath();
+	readParentDirs(getPath());
+	while (!mtpParentList.empty()) {
+		mtpParent = mtpParentList.front();
+		mtpParentList.pop_front();
+		readParentDirs(mtpParent);
+	}
+	MTPD("MtpStorage::createDB DONE\n");
+	if (use_mutex) {
+		MTPD("Starting inotify thread\n");
+		sendEvents = true;
+		inotify_thread = inotify();
+	} else {
+		MTPD("NOT starting inotify thread\n");
+	}
+	return 0;
+}
+
+MtpObjectHandleList* MtpStorage::getObjectList(MtpStorageID storageID, MtpObjectHandle parent) {
+	std::vector<int> mtpids;
+	int local_mtpparentid;
+	MTPD("MtpStorage::getObjectList\n");
+	MTPD("parent: %d\n", parent);
+	//append object id  (numerical #s) of database to int array
+	MtpObjectHandleList* list = new MtpObjectHandleList();
+	if (parent == MTP_PARENT_ROOT) {
+		MTPD("parent == MTP_PARENT_ROOT\n");
+		local_mtpparentid = 1;
+	}
+	else {
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+			MTPD("root: %d\n", i->second->Root());
+			Node* node = i->second->findNode(parent, i->second->Root());
+			if (node != NULL) {
+				local_mtpparentid = i->second->getMtpParentId(node);
+				MTPD("path: %s\n", i->second->getPath(node).c_str());
+				MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid);
+				goto endloop;
+			}
+		}
+	}
+	MTPD("got to endloop\n");
+	endloop:
+
+	if (mtpmap[local_mtpparentid] == NULL) {
+		MTPD("mtpmap[mtpparentid] == NULL, returning\n");
+		return list;
+	}
+
+	MTPD("root: %d\n", mtpmap[local_mtpparentid]->Root());
+	mtpmap[local_mtpparentid]->getmtpids(mtpmap[local_mtpparentid]->Root(), &mtpids);
+	MTPD("here, mtpids->size(): %i\n", mtpids.size());
+
+	for (unsigned index = 0; index < mtpids.size(); index++) {
+		MTPD("mtpidhere[%i]: %d\n", index, mtpids.at(index));
+		list->push(mtpids.at(index));
+	}
+	return list;
+}
+
+int MtpStorage::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
+	struct stat st;
+	uint64_t size;
+	MTPD("MtpStorage::getObjectInfo handle: %d\n", handle);
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+		Node* node = i->second->findNode(handle, i->second->Root());
+		MTPD("node returned: %d\n", node);
+		if (node != NULL) {
+				MTPD("found mtpid: %d\n", node->Mtpid());
+				info.mStorageID = getStorageID();
+				MTPD("info.mStorageID: %d\n", info.mStorageID);
+				info.mParent = node->getMtpParentId();
+				MTPD("mParent: %d\n", info.mParent);
+				lstat(node->getPath().c_str(), &st);
+				size = st.st_size;
+				MTPD("size is: %llu\n", size);
+				info.mCompressedSize = size;//(size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size);
+				info.mDateModified = st.st_mtime;
+				if (S_ISDIR(st.st_mode)) {
+					info.mFormat = MTP_FORMAT_ASSOCIATION;
+				}
+				else {
+					info.mFormat = MTP_FORMAT_UNDEFINED;
+				}
+				info.mName = strdup(basename(node->getPath().c_str()));
+				MTPD("MtpStorage::getObjectInfo found, Exiting getObjectInfo()\n");
+				return 0;
+		}
+	}
+	MTPE("MtpStorage::getObjectInfo no object found, error!\n");
+	return -1;
+}
+
+MtpObjectHandle MtpStorage::beginSendObject(const char* path,
+											MtpObjectFormat format,
+											MtpObjectHandle parent,
+											MtpStorageID storage,
+											uint64_t size,
+											time_t modified) {
+	MTPD("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format);
+	Node* node;
+	std::string parentdir;
+	std::string pathstr(path);
+	int parent_id;
+	parentdir = pathstr.substr(0, pathstr.find_last_of('/'));
+	MTPD("MtpStorage::beginSendObject() parentdir: %s\n", parentdir.c_str());
+	if (parentdir.compare(mtpstorageparent) == 0) {
+		// root directory
+		MTPD("MtpStorage::beginSendObject() root dir\n");
+		parent_id = 1;
+		++mtpid;
+		node = mtpmap[parent_id]->addNode(mtpid, path);
+		MTPD("node: %d\n", node);
+		node->addProperties(storage, 0);
+		if (format == MTP_FORMAT_ASSOCIATION) {
+			createEmptyDir(path);
+		}
+		return mtpid;
+	} else {
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			node = i->second->findNodePath(parentdir, i->second->Root());
+			if (node != NULL) {
+				MTPD("mtpid: %d\n", mtpid);
+				MTPD("path: %s\n", i->second->getPath(node).c_str());
+				parentdir = i->second->getPath(node);
+				parent = i->second->getMtpParentId(node);
+				if (parent == 0) {
+					MTPD("MtpStorage::beginSendObject parent is 0, error.\n");
+					return -1;
+				} else {
+					++mtpid;
+					node = mtpmap[parent]->addNode(mtpid, path);
+					node->addProperties(getStorageID(), getParentObject(parentdir));
+					for (iter i2 = mtpmap.begin(); i2 != mtpmap.end(); i2++) {
+						node = i2->second->findNodePath(path, i2->second->Root());
+						if (node != NULL) {
+							i2->second->setMtpParentId(parent, node);
+						}
+					}
+					if (format == MTP_FORMAT_ASSOCIATION) {
+						createEmptyDir(path);
+					}
+				}
+				return mtpid;
+			}
+		}
+	}
+	MTPE("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format);
+	return -1;
+}
+
+int MtpStorage::getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) {
+	struct stat st;
+	Node* node;
+	MTPD("MtpStorage::getObjectFilePath handle: %i\n", handle);
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+		MTPD("handle: %d\n", handle);
+		node = i->second->findNode(handle, i->second->Root());
+		MTPD("node returned: %d\n", node);
+		if (node != NULL) {
+			lstat(node->getPath().c_str(), &st);
+			outFileLength = st.st_size;
+			outFilePath = strdup(node->getPath().c_str());
+			MTPD("outFilePath: %s\n", node->getPath().c_str());
+			goto end;
+		}
+	}
+	MTPE("MtpStorage::getObjectFilePath fauled to find handle: %i\n", handle);
+	return -1;
+end:
+	outFormat = MTP_FORMAT_ASSOCIATION;
+	return 0;
+}
+
+int MtpStorage::readParentDirs(std::string path) {
+	struct dirent *de;
+	struct stat st;
+	DIR *d;
+	std::string parent, item, prevparent = "";
+	Node* node;
+	int storageID = getStorageID();
+
+	d = opendir(path.c_str());
+	MTPD("opening '%s'\n", path.c_str());
+	if (d == NULL) {
+		MTPD("error opening '%s' -- error: %s\n", path.c_str(), strerror(errno));
+		closedir(d);
+	}
+	while ((de = readdir(d)) != NULL) {
+		if (de->d_type == DT_DIR && strcmp(de->d_name, ".") == 0)
+			continue;
+		if (de->d_type == DT_DIR && strcmp(de->d_name, "..") != 0) {
+			// Handle dirs
+			item = path + "/" + de->d_name;
+			MTPD("dir: %s\n", item.c_str());
+			mtpParentList.push_back(item);
+			parent = item.substr(0, item.find_last_of('/'));
+			++mtpid;
+			MTPD("parent: %s\n", parent.c_str());
+			MTPD("mtpid: %d\n", mtpid);
+			if (prevparent != parent) {
+				mtpparentid++;
+				MTPD("Handle dirs, prevparent != parent, mtpparentid: %d\n", mtpparentid);
+				mtpmap[mtpparentid] = new Tree();
+				MTPD("prevparent addNode\n");
+				for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+					node = i->second->findNodePath(parent, i->second->Root());
+					if (node != NULL) {
+						i->second->setMtpParentId(mtpparentid, node);
+					}
+				}
+				node = mtpmap[mtpparentid]->addNode(mtpid, item);
+				node->addProperties(storageID, getParentObject(path));
+				if (sendEvents)
+					mServer->sendObjectAdded(mtpid);
+			}
+			else {
+				MTPD("add node\n");
+				mtpmap[mtpparentid]->addNode(mtpid, item);
+				for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+					node = i->second->findNodePath(item, i->second->Root());
+					if (node != NULL) {
+						i->second->setMtpParentId(mtpparentid, node);
+						node->addProperties(storageID, getParentObject(path));
+					}
+				}
+				if (sendEvents)
+					mServer->sendObjectAdded(mtpid);
+			}
+			prevparent = parent;
+		}
+		else {
+			if (strcmp(de->d_name, "..") != 0) {
+				// Handle files
+				item = path + "/" + de->d_name;
+				MTPD("file: %s\n", item.c_str());
+				parent = item.substr(0, item.find_last_of('/'));
+				MTPD("parent: %s\n", parent.c_str());
+				++mtpid;
+				MTPD("mtpid: %d\n", mtpid);
+				if (prevparent != parent) {
+					mtpparentid++;
+					MTPD("mtpparentid1: %d\n", mtpparentid);
+					for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+						node = i->second->findNodePath(path, i->second->Root());
+						if (node != NULL) {
+							i->second->setMtpParentId(mtpparentid, node);
+							node->addProperties(storageID, getParentObject(path));
+						}
+					}
+				}
+				if (mtpmap[mtpparentid] == NULL) {
+					mtpmap[mtpparentid] = new Tree();
+				}
+				MTPD("blank addNode\n");
+				node = mtpmap[mtpparentid]->addNode(mtpid, item);
+				node->addProperties(storageID, getParentObject(path));
+				prevparent = parent;
+				if (sendEvents)
+					mServer->sendObjectAdded(mtpid);
+			}
+			else {
+				// Handle empty dirs?
+				MTPD("checking for empty dir '%s'\n", path.c_str());
+				int count = 0;
+				DIR *dirc;
+				struct dirent *ep;
+				dirc = opendir(path.c_str());
+				if (dirc != NULL) {
+					while ((ep = readdir(dirc)))
+						++count;
+					MTPD("count: %d\n", count);
+					closedir(dirc);
+				}
+				if (count == 2) {
+					MTPD("'%s' is an empty dir\n", path.c_str());
+					createEmptyDir(path.c_str());
+					goto end;
+				}
+			}
+		}
+	}
+	end:
+		closedir(d);
+		return 0;
+}
+
+void MtpStorage::deleteTrees(int parent) {
+	Node* node = mtpmap[parent]->Root();
+	MTPD("MtpStorage::deleteTrees deleting %i\n", parent);
+	while (node != NULL) {
+		if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) {
+			deleteTrees(node->getMtpParentId());
+		}
+		node = mtpmap[parent]->getNext(node);
+	}
+	delete mtpmap[parent];
+	mtpmap.erase(parent);
+	MTPD("MtpStorage::deleteTrees deleted %i\n", parent);
+}
+
+int MtpStorage::deleteFile(MtpObjectHandle handle) {
+	int local_parent_id = 0;
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+		MTPD("MtpStorage::deleteFile handle: %d\n", handle);
+		Node* node = i->second->findNode(handle, i->second->Root());
+		MTPD("MtpStorage::deleteFile node returned: %d\n", node);
+		if (node != NULL) {
+			if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) {
+				local_parent_id = node->getMtpParentId();
+			}
+			MTPD("deleting handle: %d\n", handle);
+			i->second->deleteNode(handle);
+			MTPD("deleted\n");
+			goto end;
+		}
+	}
+	MTPE("MtpStorage::deleteFile deleting handle: %d FAILED\n", handle);
+	return -1;
+end:
+	if (local_parent_id) {
+		deleteTrees(local_parent_id);
+	}
+	return 0;
+}
+
+int MtpStorage::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) {
+	Node *n;
+	int local_mtpid = 0;
+	int local_mtpparentid = 0;
+	std::vector<int> propertyCodes;
+	std::vector<int> dataTypes;
+	std::vector<std::string> valueStrs;
+	std::vector<int> longValues;
+	int count = 0;
+	MTPD("MtpStorage::getObjectPropertyList handle: %d, format: %d, property: %lx\n", handle, format, property);
+	if (property == MTP_PROPERTY_OBJECT_FORMAT) {
+		MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_FORMAT\n");
+		MTPD("mtpmap count: %d\n", mtpmap.size());
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node *node = i->second->findNode(handle, i->second->Root());
+			MTPD("index: %d\n", index);
+			MTPD("node: %d\n", node);
+			if (node != NULL) {
+				uint64_t longval = node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT);
+				local_mtpparentid = i->second->getMtpParentId(node);
+				MTPD("object format longValue: %llu\n", longval);
+				propertyCodes.push_back(MTP_PROPERTY_OBJECT_FORMAT);
+				longValues.push_back(node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT));
+				valueStrs.push_back("");
+				dataTypes.push_back(4);
+				count = 1;
+				local_mtpid = node->Mtpid();
+				goto endloop;
+			}
+		}
+	}
+	else if (property == MTP_PROPERTY_STORAGE_ID) {
+		MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_STORAGE_ID\n");
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node *node = i->second->findNode(handle, i->second->Root());
+			if (node != NULL) {
+				propertyCodes.push_back(MTP_PROPERTY_STORAGE_ID);
+				longValues.push_back(getStorageID());
+				valueStrs.push_back("");
+				dataTypes.push_back(4);
+				count = 1;
+				local_mtpid = node->Mtpid();
+				goto endloop;
+			}
+		}
+	}
+	else if (property == MTP_PARENT_ROOT) {
+		MTPD("MtpStorage::getObjectPropertyList MTP_PARENT_ROOT\n");
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node* node = i->second->findNode(handle, i->second->Root());
+			if (node != NULL) {
+				local_mtpparentid = i->second->getMtpParentId(node);
+				MTPD("path: %s\n", i->second->getPath(node).c_str());
+				MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid);
+				std::vector<Node::mtpProperty> mtpprop = node->getMtpProps();
+				count = mtpprop.size();
+				for (int i = 0; i < count; ++i) {
+					propertyCodes.push_back(mtpprop[i].property);
+					longValues.push_back(mtpprop[i].valueInt);
+					valueStrs.push_back(mtpprop[i].valueStr);
+					dataTypes.push_back(mtpprop[i].dataType);
+				}
+				local_mtpid = node->Mtpid();
+				goto endloop;
+			}
+		}
+	}
+	else if (property == MTP_PROPERTY_PROTECTION_STATUS) {
+		MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_PROTECTION_STATUS\n");
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node *node = i->second->findNode(handle, i->second->Root());
+			if (node != NULL) {
+				propertyCodes.push_back(MTP_PROPERTY_PROTECTION_STATUS);
+				longValues.push_back(0);
+				valueStrs.push_back("");
+				dataTypes.push_back(8);
+				count = 1;
+				local_mtpid = node->Mtpid();
+				goto endloop;
+			}
+		}
+	}
+	else if (property == MTP_PROPERTY_OBJECT_SIZE) {
+		MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_SIZE\n");
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node *node = i->second->findNode(handle, i->second->Root());
+			if (node != NULL) {
+				struct stat st;
+				uint64_t size;
+				lstat(node->getPath().c_str(), &st);
+				size = st.st_size;
+				propertyCodes.push_back(MTP_PROPERTY_OBJECT_SIZE);
+				longValues.push_back(size);
+				valueStrs.push_back("");
+				dataTypes.push_back(8);
+				count = 1;
+				local_mtpid = node->Mtpid();
+				goto endloop;
+			}
+		}
+	}
+	else {
+		MTPE("MtpStorage::getObjectPropertyList unsupported property %x\n", property);
+		return -1;
+	}
+
+endloop:
+	MTPD("mtpparentid: %d\n", local_mtpparentid);
+	MTPD("count: %d\n", count);
+	packet.putUInt32(count);
+
+	if (count > 0) {
+		std::string stringValuesArray;
+		for (int i = 0; i < count; ++i) {
+			packet.putUInt32(local_mtpid);
+			packet.putUInt16(propertyCodes[i]);
+			MTPD("dataTypes: %d\n", dataTypes[i]);
+			packet.putUInt16(dataTypes[i]);
+			MTPD("propertyCode: %s\n", MtpDebug::getObjectPropCodeName(propertyCodes[i]));
+			MTPD("longValues: %d\n", longValues[i]);
+			switch (dataTypes[i]) {
+				case MTP_TYPE_INT8:
+					MTPD("MTP_TYPE_INT8\n");
+					packet.putInt8(longValues[i]);
+					break;
+				case MTP_TYPE_UINT8:
+					MTPD("MTP_TYPE_UINT8\n");
+					packet.putUInt8(longValues[i]);
+					break;
+				case MTP_TYPE_INT16:
+					MTPD("MTP_TYPE_INT16\n");
+					packet.putInt16(longValues[i]);
+					break;
+				case MTP_TYPE_UINT16:
+					MTPD("MTP_TYPE_UINT16\n");
+					packet.putUInt16(longValues[i]);
+					break;
+				case MTP_TYPE_INT32:
+					MTPD("MTP_TYPE_INT32\n");
+					packet.putInt32(longValues[i]);
+					break;
+				case MTP_TYPE_UINT32:
+					MTPD("MTP_TYPE_UINT32\n");
+					packet.putUInt32(longValues[i]);
+					break;
+				case MTP_TYPE_INT64:
+					MTPD("MTP_TYPE_INT64\n");
+					packet.putInt64(longValues[i]);
+					break;
+				case MTP_TYPE_UINT64:
+					MTPD("MTP_TYPE_UINT64\n");
+					packet.putUInt64(longValues[i]);
+					break;
+				case MTP_TYPE_INT128:
+					MTPD("MTP_TYPE_INT128\n");
+					packet.putInt128(longValues[i]);
+					break;
+				case MTP_TYPE_UINT128:
+					MTPD("MTP_TYPE_UINT128\n");
+					packet.putUInt128(longValues[i]);
+					break;
+				case MTP_TYPE_STR:
+					MTPD("MTP_TYPE_STR: %s\n", valueStrs[i].c_str());
+					packet.putString((const char*) valueStrs[i].c_str());
+					break;
+				default:
+					MTPE("bad or unsupported data type: %i in MyMtpDatabase::getObjectPropertyList", dataTypes[i]);
+					break;
+			}
+		}
+	}
+	return 0;
+}
+
+int MtpStorage::renameObject(MtpObjectHandle handle, std::string newName) {
+	int index;
+	MTPD("MtpStorage::renameObject, handle: %d, new name: '%s'\n", handle, newName.c_str());
+	if (handle == MTP_PARENT_ROOT) {
+		MTPE("parent == MTP_PARENT_ROOT, cannot rename root\n");
+		return -1;
+	} else {
+		for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+			MTPD("root: %d\n", i->second->Root());
+			Node* node = i->second->findNode(handle, i->second->Root());
+			if (node != NULL) {
+				std::string oldName = i->second->getPath(node);
+				std::string parentdir = oldName.substr(0, oldName.find_last_of('/'));
+				std::string newFullName = parentdir + "/" + newName;
+				MTPD("old: '%s', new: '%s'\n", oldName.c_str(), newFullName.c_str());
+				if (rename(oldName.c_str(), newFullName.c_str()) == 0) {
+					node->setPath(newFullName);
+					return 0;
+				} else {
+					MTPE("MtpStorage::renameObject failed, handle: %d, new name: '%s'\n", handle, newName.c_str());
+					return -1;
+				}
+			}
+		}
+	}
+	MTPE("MtpStorage::renameObject handle / node not found, error!\n");
+	return -1;
+}
+
+void MtpStorage::createEmptyDir(const char* path) {
+	Node *node;
+	++mtpparentid;
+	MtpStorageID storage = getStorageID();
+	MTPD("MtpStorage::createEmptyDir path: '%s', storage: %i, mtpparentid: %d\n", path, storage, mtpparentid);
+	mtpmap[mtpparentid] = new Tree();
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+		node = i->second->findNodePath(path, i->second->Root());
+		if (node != NULL) {
+			mtpmap[mtpparentid]->setMtpParentId(mtpparentid, node);
+		}
+	}
+}
+
+int MtpStorage::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, uint64_t &longValue) {
+	Node *node;
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
+		node = i->second->findNode(handle, i->second->Root());
+		if (node != NULL) {
+			longValue = node->getIntProperty(property);
+			return 0;
+		}
+	}
+	MTPE("MtpStorage::getObjectPropertyValue unable to locate handle: %i\n", handle);
+	return -1;
+}
+pthread_t MtpStorage::inotify(void) {
+	pthread_t thread;
+	ThreadPtr inotifyptr = &MtpStorage::inotify_t;
+	PThreadPtr p = *(PThreadPtr*)&inotifyptr;
+	pthread_create(&thread, NULL, p, this);
+	return thread;
+}
+
+int MtpStorage::addInotifyDirs(std::string path) {
+	struct dirent *de;
+	DIR *d;
+	struct stat st;
+	std::string inotifypath;
+
+	d = opendir(path.c_str());
+	if (d == NULL) {
+		MTPE("MtpStorage::addInotifyDirs unable to open '%s'\n", path.c_str());
+		closedir(d);
+		return -1;
+	}
+
+	while ((de = readdir(d)) != NULL) {
+		if (de->d_type != DT_DIR || strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+		inotifypath = path + "/" + de->d_name;
+		if (addInotifyDirs(inotifypath)) {
+			closedir(d);
+			return -1;
+		}
+		inotify_wd = inotify_add_watch(inotify_fd, inotifypath.c_str(), IN_CREATE | IN_DELETE);
+		inotifymap[inotify_wd] = inotifypath;
+		MTPD("added inotify dir: '%s'\n", inotifypath.c_str());
+	}
+	closedir(d);
+	return 0;
+}
+
+int MtpStorage::inotify_t(void) {
+	int len, i = 0;
+	int local_mtpparentid;
+	Node* node = NULL;
+	struct stat st;
+	#define EVENT_SIZE ( sizeof(struct inotify_event) )
+	#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16) )
+	char buf[EVENT_BUF_LEN];
+	std::string item, parent = "";
+
+	MTPD("starting inotify thread\n");
+	inotify_fd = inotify_init();
+
+	if (inotify_fd < 0){
+		MTPE("Can't run inotify for mtp server\n");
+	}
+
+	inotify_wd = inotify_add_watch(inotify_fd, getPath(), WATCH_FLAGS);
+	inotifymap[inotify_wd] = getPath();
+	if (addInotifyDirs(getPath())) {
+		MTPE("MtpStorage::inotify_t failed to add watches to directories\n");
+		for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+			inotify_rm_watch(inotify_fd, i->first);
+		}
+		close(inotify_fd);
+		return -1;
+	}
+
+	while (true) {
+		i = 0;
+		len = read(inotify_fd, buf, EVENT_BUF_LEN);
+
+		if (len < 0) {
+			MTPE("inotify_t Can't read inotify events\n");
+		}
+
+		while (i < len) {
+			struct inotify_event *event = ( struct inotify_event * ) &buf[ i ];
+			if ( event->len ) {
+				if (inotifymap[event->wd].empty()) {
+					MTPE("Unable to locate inotify_wd: %i\n", event->wd);
+					goto end;
+				} else {
+					item = inotifymap[event->wd];
+					item = item	+ "/" + event->name;
+					MTPD("inotify_t item: '%s'\n", item.c_str());
+					if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) {
+						lockMutex(1);
+						if (event->mask & IN_ISDIR) {
+							MTPD("inotify_t create is dir\n");
+						} else {
+							MTPD("inotify_t create is file\n");
+						}
+						for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+							node = i->second->findNodePath(item, i->second->Root());
+							if (node != NULL)
+								break;
+						}
+						if (node == NULL) {
+							parent = item.substr(0, item.find_last_of('/'));
+							MTPD("parent: %s\n", parent.c_str());
+							if (parent == getPath()) {
+								local_mtpparentid = 1;
+							} else {
+								for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+									node = i->second->findNodePath(parent, i->second->Root());
+									MTPD("searching for node: %d\n", (int)node);
+									if (node != NULL) {
+										local_mtpparentid = i->second->getMtpParentId(node);
+										break;
+									}
+								}
+								if (node == NULL) {
+									MTPE("inotify_t unable to locate mtparentid\n");
+									goto end;
+								}
+							}
+							++mtpid;
+							MTPD("mtpid: %d\n", mtpid);
+							MTPD("mtpparentid1: %d\n", local_mtpparentid);
+							node = mtpmap[local_mtpparentid]->addNode(mtpid, item);
+							mtpmap[local_mtpparentid]->setMtpParentId(local_mtpparentid, node);
+							node->addProperties(getStorageID(), getParentObject(parent));
+							if (event->mask & IN_ISDIR) {
+								createEmptyDir(item.c_str());
+							}
+							mServer->sendObjectAdded(mtpid);
+						} else {
+							MTPD("inotify_t item already exists.\n");
+						}
+						if (event->mask & IN_ISDIR) {
+							inotify_wd = inotify_add_watch(inotify_fd, item.c_str(), WATCH_FLAGS);
+							inotifymap[inotify_wd] = item;
+							MTPD("added inotify dir: '%s'\n", item.c_str());
+							MTPD("inotify_t scanning new dir\n");
+							readParentDirs(item);
+							std::string mtpParent;
+							while (!mtpParentList.empty()) {
+								mtpParent = mtpParentList.front();
+								mtpParentList.pop_front();
+								readParentDirs(mtpParent);
+								inotify_wd = inotify_add_watch(inotify_fd, mtpParent.c_str(), WATCH_FLAGS);
+								inotifymap[inotify_wd] = mtpParent;
+								MTPD("added inotify dir: '%s'\n", mtpParent.c_str());
+							}
+						}
+					} else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) {
+						lockMutex(1);
+						if (event->mask & IN_ISDIR) {
+							MTPD("inotify_t Directory %s deleted\n", event->name);
+						} else {
+							MTPD("inotify_t File %s deleted\n", event->name);
+						}
+						for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+							node = i->second->findNodePath(item, i->second->Root());
+							if (node != NULL)
+								break;
+						}
+						if (node != NULL && node->Mtpid() > 0) {
+							int local_id = node->Mtpid();
+							node = NULL;
+							deleteFile(local_id);
+							mServer->sendObjectRemoved(local_id);
+						} else {
+							MTPD("inotify_t already removed.\n");
+						}
+						if (event->mask & IN_ISDIR) {
+							std::string orig_item = item + "/";
+							size_t item_size = orig_item.size();
+							std::string path_check;
+							for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+								if ((i->second.size() > item_size && i->second.substr(0, item_size) == orig_item) || i->second == item) {
+									inotify_rm_watch(inotify_fd, i->first);
+									MTPD("inotify_t removing watch on '%s'\n", i->second.c_str());
+									inotifymap.erase(i->first);
+								}
+							}
+						}
+					} else if (event->mask & IN_MODIFY) {
+						MTPD("inotify_t item %s modified.\n", event->name);
+						for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+							node = i->second->findNodePath(item, i->second->Root());
+							if (node != NULL)
+								break;
+						}
+						if (node != NULL) {
+							uint64_t orig_size = node->getIntProperty(MTP_PROPERTY_OBJECT_SIZE);
+							struct stat st;
+							lstat(item.c_str(), &st);
+							uint64_t new_size = (uint64_t)st.st_size;
+							if (orig_size != new_size) {
+								MTPD("size changed from %llu to %llu on mtpid: %i\n", orig_size, new_size, node->Mtpid());
+								node->updateProperty(MTP_PROPERTY_OBJECT_SIZE, new_size, "", MTP_TYPE_UINT64);
+								mServer->sendObjectUpdated(node->Mtpid());
+							}
+						} else {
+							MTPE("inotify_t modified item not found\n");
+						}
+					}
+				}
+			}
+end:
+			unlockMutex(1);
+			i += EVENT_SIZE + event->len;
+		}
+	}
+
+	for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+		inotify_rm_watch(inotify_fd, i->first);
+	}
+	close(inotify_fd);
+	return 0;
+}
+
+int MtpStorage::getParentObject(std::string parent_path) {
+	Node* node;
+	if (parent_path == getPath()) {
+		MTPD("MtpStorage::getParentObject for: '%s' returning: 0 for root\n", parent_path.c_str());
+		return 0;
+	}
+	for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
+		node = i->second->findNodePath(parent_path, i->second->Root());
+		if (node != NULL) {
+			MTPD("MtpStorage::getParentObject for: '%s' returning: %i\n", parent_path.c_str(), node->Mtpid());
+			return node->Mtpid();
+		}
+	}
+	MTPE("MtpStorage::getParentObject for: '%s' unable to locate node\n", parent_path.c_str());
+	return -1;
+}
+
+void MtpStorage::lockMutex(int thread_type) {
+	if (!use_mutex)
+		return; // mutex is disabled
+	if (thread_type) {
+		// inotify thread
+		pthread_mutex_lock(&inMutex);
+		while (pthread_mutex_trylock(&mtpMutex)) {
+			pthread_mutex_unlock(&inMutex);
+			usleep(32000);
+			pthread_mutex_lock(&inMutex);
+		}
+	} else {
+		// main mtp thread
+		pthread_mutex_lock(&mtpMutex);
+		while (pthread_mutex_trylock(&inMutex)) {
+			pthread_mutex_unlock(&mtpMutex);
+			usleep(13000);
+			pthread_mutex_lock(&mtpMutex);
+		}
+	}
+}
+
+void MtpStorage::unlockMutex(int thread_type) {
+	if (!use_mutex)
+		return; // mutex is disabled
+	pthread_mutex_unlock(&inMutex);
+	pthread_mutex_unlock(&mtpMutex);
+}
diff --git a/mtp/MtpStorage.h b/mtp/MtpStorage.h
new file mode 100755
index 0000000..ad828d1
--- /dev/null
+++ b/mtp/MtpStorage.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_STORAGE_H
+#define _MTP_STORAGE_H
+
+#include "mtp.h"
+#include "MtpObjectInfo.h"
+#include <string>
+#include <deque>
+#include <map>
+#include <libgen.h>
+#include <pthread.h>
+#include "btree.hpp"
+#include "MtpServer.h"
+
+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;
+	MtpServer*				mServer;
+	std::deque<std::string> mtpParentList;
+	int mtpparentid;
+    Tree *mtpdbtree;
+    typedef std::map<int, Tree*> maptree;
+    typedef maptree::iterator iter;
+    maptree mtpmap;
+	std::string mtpstorageparent;
+	pthread_t inotify_thread;
+	int inotify_fd;
+	int inotify_wd;
+	android::Mutex           mMutex;
+
+public:
+                            MtpStorage(MtpStorageID id, const char* filePath,
+                                    const char* description, uint64_t reserveSpace,
+                                    bool removable, uint64_t maxFileSize, MtpServer* refserver);
+    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 (const char *)mFilePath; }
+    inline bool             isRemovable() const { return mRemovable; }
+    inline uint64_t         getMaxFileSize() const { return mMaxFileSize; }
+	int readParentDirs(std::string path);
+	int createDB();
+	MtpObjectHandleList* getObjectList(MtpStorageID storageID, MtpObjectHandle parent);
+	int getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info);
+	MtpObjectHandle beginSendObject(const char* path, MtpObjectFormat format, MtpObjectHandle parent, MtpStorageID storage, uint64_t size, time_t modified);
+	int getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet);
+	int getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat);
+	int deleteFile(MtpObjectHandle handle);
+	int renameObject(MtpObjectHandle handle, std::string newName);
+	int getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, uint64_t &longValue);
+	void lockMutex(int thread_type);
+	void unlockMutex(int thread_type);
+
+private:
+	void createEmptyDir(const char* path);
+	pthread_t inotify();
+	int inotify_t();
+	typedef int (MtpStorage::*ThreadPtr)(void);
+	typedef void* (*PThreadPtr)(void *);
+	std::map<int, std::string> inotifymap;
+	int addInotifyDirs(std::string path);
+	void deleteTrees(int parent);
+	bool sendEvents;
+	int getParentObject(std::string parent_path);
+	bool use_mutex;
+	pthread_mutex_t inMutex; // inotify mutex
+	pthread_mutex_t mtpMutex; // main mtp mutex
+};
+
+#endif // _MTP_STORAGE_H
diff --git a/mtp/MtpStorageInfo.cpp b/mtp/MtpStorageInfo.cpp
new file mode 100755
index 0000000..a2b8ca2
--- /dev/null
+++ b/mtp/MtpStorageInfo.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include "MtpDebug.h"
+#include "MtpDataPacket.h"
+#include "MtpStorageInfo.h"
+#include "MtpStringBuffer.h"
+
+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() {
+	MTPI("Storage Info %08X:\n\tmStorageType: %d\n\tmFileSystemType: %d\n\tmAccessCapability: %d\n",
+			mStorageID, mStorageType, mFileSystemType, mAccessCapability);
+	MTPI("\tmMaxCapacity: %lld\n\tmFreeSpaceBytes: %lld\n\tmFreeSpaceObjects: %d\n",
+			mMaxCapacity, mFreeSpaceBytes, mFreeSpaceObjects);
+	MTPI("\tmStorageDescription: %s\n\tmVolumeIdentifier: %s\n",
+			mStorageDescription, mVolumeIdentifier);
+}
+
diff --git a/mtp/MtpStorageInfo.h b/mtp/MtpStorageInfo.h
new file mode 100755
index 0000000..8858328
--- /dev/null
+++ b/mtp/MtpStorageInfo.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_STORAGE_INFO_H
+#define _MTP_STORAGE_INFO_H
+
+#include "MtpTypes.h"
+
+
+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();
+};
+
+
+#endif // _MTP_STORAGE_INFO_H
diff --git a/mtp/MtpStringBuffer.cpp b/mtp/MtpStringBuffer.cpp
new file mode 100755
index 0000000..8aeb3ca
--- /dev/null
+++ b/mtp/MtpStringBuffer.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <string.h>
+#include "MtpDataPacket.h"
+#include "MtpStringBuffer.h"
+
+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) {
+	size_t 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);
+}
+
diff --git a/mtp/MtpStringBuffer.h b/mtp/MtpStringBuffer.h
new file mode 100755
index 0000000..9d61ecf
--- /dev/null
+++ b/mtp/MtpStringBuffer.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_STRING_BUFFER_H
+#define _MTP_STRING_BUFFER_H
+
+#include <stdint.h>
+
+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; }
+};
+
+#endif // _MTP_STRING_BUFFER_H
diff --git a/mtp/MtpTypes.h b/mtp/MtpTypes.h
new file mode 100755
index 0000000..64e180c
--- /dev/null
+++ b/mtp/MtpTypes.h
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_TYPES_H
+#define _MTP_TYPES_H
+
+#include <stdint.h>
+#include <vector>
+#include <utils/Vector.h>
+#include <utils/String8.h>
+
+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;
+
+typedef android::Vector<MtpStorage*> MtpStorageList;
+typedef android::Vector<MtpDevice*> MtpDeviceList;
+typedef android::Vector<MtpProperty*> MtpPropertyList;
+
+typedef android::Vector<uint8_t> UInt8List;
+typedef android::Vector<uint16_t> UInt16List;
+typedef android::Vector<uint32_t> UInt32List;
+typedef android::Vector<uint64_t> UInt64List;
+typedef android::Vector<int8_t> Int8List;
+typedef android::Vector<int16_t> Int16List;
+typedef android::Vector<int32_t> Int32List;
+typedef android::Vector<int64_t> Int64List;
+
+typedef UInt16List MtpObjectPropertyList;
+typedef UInt16List MtpDevicePropertyList;
+typedef UInt16List MtpObjectFormatList;
+typedef UInt32List MtpObjectHandleList;
+typedef UInt16List MtpObjectPropertyList;
+typedef UInt32List MtpStorageIDList;
+
+typedef android::String8    MtpString;
+
+
+#endif // _MTP_TYPES_H
diff --git a/mtp/MtpUtils.cpp b/mtp/MtpUtils.cpp
new file mode 100755
index 0000000..5fa32f2
--- /dev/null
+++ b/mtp/MtpUtils.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+#include <cutils/tztime.h>
+#include "MtpUtils.h"
+
+
+/*
+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;
+	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;
+	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);
+}
+
diff --git a/mtp/MtpUtils.h b/mtp/MtpUtils.h
new file mode 100755
index 0000000..2bca94b
--- /dev/null
+++ b/mtp/MtpUtils.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_UTILS_H
+#define _MTP_UTILS_H
+
+#include <stdint.h>
+
+bool parseDateTime(const char* dateTime, time_t& outSeconds);
+void formatDateTime(time_t seconds, char* buffer, int bufferLength);
+
+#endif // _MTP_UTILS_H
diff --git a/mtp/btree.cpp b/mtp/btree.cpp
new file mode 100755
index 0000000..7976ac3
--- /dev/null
+++ b/mtp/btree.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ * 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 <iostream>
+#include <utils/threads.h>
+#include "btree.hpp"
+#include "MtpDebug.h"
+
+// Constructor
+Tree::Tree() {
+	root = NULL;
+	count = 0;
+}
+
+// Destructor
+Tree::~Tree() {
+	freeNode(root);
+}
+
+// Free the node
+void Tree::freeNode(Node* leaf)
+{
+	if ( leaf != NULL )
+	{
+		freeNode(leaf->Left());
+		freeNode(leaf->Right());
+		delete leaf;
+	}
+}
+
+int Tree::getCount(void) {
+	MTPD("node count: %d\n", count);
+	return count;
+}
+
+Node* Tree::addNode(int mtpid, std::string path)
+{
+	MTPD("root: %d\n", root);
+	// No elements. Add the root
+	if ( root == NULL ) {
+		Node* n = new Node();
+		count++;
+		MTPD("node count: %d\n", count);
+		MTPD("adding node address: %d\n", n);
+		MTPD("adding mtpid: %d\n", mtpid);
+		n->setMtpid(mtpid);
+		n->setPath(path);
+		root = n;
+		MTPD("set root to %d\n", root);
+		return n;
+	}
+	else {
+		count++;
+		MTPD("node count: %d\n", count);
+		MTPD("adding new child node\n");
+		return addNode(mtpid, root, path);
+	}
+}
+
+// Add a node (private)
+Node* Tree::addNode(int mtpid, Node* leaf, std::string path) {
+	Node* n;
+	if ( mtpid <= leaf->Mtpid() )
+	{
+		if ( leaf->Left() != NULL )
+			return addNode(mtpid, leaf->Left(), path);
+		else {
+			n = new Node();
+			MTPD("adding mtpid: %d node: %d\n", mtpid, n);
+			n->setMtpid(mtpid);
+			n->setPath(path);
+			n->setParent(leaf);
+			leaf->setLeft(n);
+		}
+	}
+	else
+	{
+		if ( leaf->Right() != NULL )
+			return addNode(mtpid, leaf->Right(), path);
+		else {
+			n = new Node();
+			MTPD("adding mtpid: %d node: %d\n", mtpid, n);
+			n->setMtpid(mtpid);
+			n->setPath(path);
+			n->setParent(leaf);
+			leaf->setRight(n);
+		}
+	}
+	return n;
+}
+
+void Tree::setMtpParentId(int mtpparentid, Node* node) {
+	node->setMtpParentId(mtpparentid);
+}
+
+std::string Tree::getPath(Node* node) {
+	return node->getPath();
+}
+
+int Tree::getMtpParentId(Node* node) {
+	return node->getMtpParentId();
+}
+
+Node* Tree::findNodePath(std::string path, Node* node) {
+	Node* n;
+	if ( node == NULL ) {
+		return NULL;
+	}
+	if ( node->getPath().compare(path) == 0 && node->Mtpid() > 0) {
+		return node;
+	}
+	else {
+		n = findNodePath(path, node->Left());
+		if (n)
+			return n;
+		n = findNodePath(path, node->Right());
+		if (n)
+			return n;
+	}
+	return NULL;
+}
+
+Node* Tree::getNext(Node *node) {
+	if (node == NULL)
+		return NULL;
+	else {
+		if (node->Left() != NULL)
+			return node->Left();
+		if (node->Right() != NULL)
+			return node->Right();
+	}
+	return NULL;
+}
+
+Node* Tree::findNode(int key, Node* node) {
+	//MTPD("key: %d\n", key);
+	//MTPD("node: %d\n", node);
+	if ( node == NULL ) {
+		return NULL;
+	}
+	else if ( node->Mtpid() == key ) {
+		return node;
+	}
+	else if ( key <= node->Mtpid() ) {
+		return findNode(key, node->Left());
+	}
+	else if ( key > node->Mtpid() ) {
+		return findNode(key, node->Right());
+	}
+	else {
+		return NULL;
+	}
+	return NULL;
+}
+
+void Tree::getmtpids(Node* node, std::vector<int>* mtpids)
+{
+	if ( node )
+	{
+		MTPD("node: %d\n", node->Mtpid());
+		mtpids->push_back(node->Mtpid());
+		if (node->Left())
+			getmtpids(node->Left(), mtpids);
+		if (node->Right())
+			getmtpids(node->Right(), mtpids);
+	} else {
+		mtpids->push_back(0);
+	}
+	return;
+}
+
+// Find the node with min key
+// Traverse the left sub-tree recursively
+// till left sub-tree is empty to get min
+Node* Tree::min(Node* node)
+{
+	if ( node == NULL )
+		return NULL;
+
+	if ( node->Left() )
+		min(node->Left());
+	else
+		return node;
+	return NULL;
+}
+
+// Find the node with max key
+// Traverse the right sub-tree recursively
+// till right sub-tree is empty to get max
+Node* Tree::max(Node* node)
+{
+	if ( node == NULL )
+		return NULL;
+
+	if ( node->Right() )
+		max(node->Right());
+	else
+		return node;
+	return NULL;
+}
+
+// Find successor to a node
+// Find the node, get the node with max value
+// for the right sub-tree to get the successor
+Node* Tree::successor(int key, Node *node)
+{
+	Node* thisKey = findNode(key, node);
+	if ( thisKey )
+		return max(thisKey->Right());
+	return NULL;
+}
+
+// Find predecessor to a node
+// Find the node, get the node with max value
+// for the left sub-tree to get the predecessor
+Node* Tree::predecessor(int key, Node *node)
+{
+	Node* thisKey = findNode(key, node);
+	if ( thisKey )
+		return max(thisKey->Left());
+	return NULL;
+}
+
+void Tree::deleteNode(int key)
+{
+	// Find the node.
+	Node* thisKey = findNode(key, root);
+	MTPD("Tree::deleteNode found node: %d\n", thisKey);
+	MTPD("handle: %d\n", thisKey->Mtpid());
+
+	if (thisKey == root) {
+		if (thisKey->Right()) {
+			root = thisKey->Right();
+			root->setParent(NULL);
+			return;
+		}
+		if (thisKey->Left()) {
+			root = thisKey->Left();
+			root->setParent(NULL);
+			return;
+		}
+		root = NULL;
+		delete thisKey;
+		return;
+	}
+
+	if ( thisKey->Left() == NULL && thisKey->Right() == NULL )
+	{
+		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() ) {
+			thisKey->Parent()->setRight(NULL);
+		}
+		else {
+			thisKey->Parent()->setLeft(NULL);
+		}
+		delete thisKey;
+		return;
+	}
+
+	if ( thisKey->Left() == NULL && thisKey->Right() != NULL )
+	{
+		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() )
+			thisKey->Parent()->setRight(thisKey->Right());
+		else
+			thisKey->Parent()->setLeft(thisKey->Right());
+		thisKey->Right()->setParent(thisKey->Parent());
+		delete thisKey;
+		return;
+	}
+	if ( thisKey->Left() != NULL && thisKey->Right() == NULL )
+	{
+		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() )
+			thisKey->Parent()->setRight(thisKey->Left());
+		else
+			thisKey->Parent()->setLeft(thisKey->Left());
+		thisKey->Left()->setParent(thisKey->Parent());
+		delete thisKey;
+		return;
+	}
+
+	if ( thisKey->Left() != NULL && thisKey->Right() != NULL )
+	{
+		Node* sub = predecessor(thisKey->Mtpid(), thisKey);
+		if ( sub == NULL )
+			sub = successor(thisKey->Mtpid(), thisKey);
+
+		if ( sub->Parent()->Mtpid() <= sub->Mtpid() )
+			sub->Parent()->setRight(sub->Right());
+		else
+			sub->Parent()->setLeft(sub->Left());
+
+		thisKey->setMtpid(sub->Mtpid());
+		delete sub;
+		return;
+	}
+}
diff --git a/mtp/btree.hpp b/mtp/btree.hpp
new file mode 100755
index 0000000..d6bd0c3
--- /dev/null
+++ b/mtp/btree.hpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ * 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 BTREE_HPP
+#define BTREE_HPP
+
+#include <iostream>
+#include <vector>
+#include <utils/threads.h>
+#include "MtpDebug.h"
+
+// A generic tree node class
+class Node {
+	int mtpid;
+	int mtpparentid;
+	std::string path;
+	int parentID;
+	Node* left;
+	Node* right;
+	Node* parent;
+
+public:
+	Node();
+	void setMtpid(int aMtpid);
+	void setPath(std::string aPath);
+	void setLeft(Node* aLeft);
+	void setRight(Node* aRight);
+	void setParent(Node* aParent);
+	void setMtpParentId(int id);
+	int Mtpid();
+	int getMtpParentId();
+	std::string getPath();
+	Node* Left();
+	Node* Right();
+	Node* Parent();
+	void addProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType);
+	void updateProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType);
+	void addProperties(int storageID, int parent_object);
+	uint64_t getIntProperty(uint64_t property);
+	struct mtpProperty {
+		uint64_t property;
+		uint64_t valueInt;
+		std::string valueStr;
+		int dataType;
+	};
+	std::vector<mtpProperty>& getMtpProps();
+	std::vector<mtpProperty> mtpProp;
+};
+
+// Binary Search Tree class
+class Tree {
+	Node* root;
+public:
+	Tree();
+	~Tree();
+	Node* Root() {
+		MTPD("root: %d\n", root);
+		return root; 
+	};
+	Node* addNode(int mtpid, std::string path);
+	void setMtpParentId(int mtpparentid, Node* node);
+	Node* findNode(int key, Node* parent);
+	void getmtpids(Node* node, std::vector<int>* mtpids);
+	void deleteNode(int key);
+	Node* min(Node* node);
+	Node* max(Node* node);
+	Node* successor(int key, Node* parent);
+	Node* predecessor(int key, Node* parent);
+	std::string getPath(Node* node);
+	int getMtpParentId(Node* node);
+	Node* findNodePath(std::string path, Node* node);
+	Node* getNext(Node* node);
+	int getCount();
+
+private:
+	Node* addNode(int mtpid, Node* leaf, std::string path);
+	void freeNode(Node* leaf);
+	int count;
+};
+
+#endif
diff --git a/mtp/mtp.h b/mtp/mtp.h
new file mode 100755
index 0000000..c329331
--- /dev/null
+++ b/mtp/mtp.h
@@ -0,0 +1,607 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTP_H
+#define _MTP_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#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
+
+// Supported Playback Formats
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED 0x3000
+/** Format code for associations (folders and directories) */
+#define SUPPORTED_PLAYBACK_FORMAT_ASSOCIATION 0x3001
+/** Format code for script files */
+#define SUPPORTED_PLAYBACK_FORMAT_SCRIPT 0x3002
+/** Format code for executable files */
+#define SUPPORTED_PLAYBACK_FORMAT_EXECUTABLE 0x3003
+/** Format code for text files */
+#define SUPPORTED_PLAYBACK_FORMAT_TEXT 0x3004
+/** Format code for HTML files */
+#define SUPPORTED_PLAYBACK_FORMAT_HTML 0x3005
+/** Format code for DPOF files */
+#define SUPPORTED_PLAYBACK_FORMAT_DPOF 0x3006
+/** Format code for AIFF audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_AIFF 0x3007
+/** Format code for WAV audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_WAV 0x3008
+/** Format code for MP3 audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_MP3 0x3009
+/** Format code for AVI video files */
+#define SUPPORTED_PLAYBACK_FORMAT_AVI 0x300A
+/** Format code for MPEG video files */
+#define SUPPORTED_PLAYBACK_FORMAT_MPEG 0x300B
+/** Format code for ASF files */
+#define SUPPORTED_PLAYBACK_FORMAT_ASF 0x300C
+/** Format code for JPEG image files */
+#define SUPPORTED_PLAYBACK_FORMAT_EXIF_JPEG 0x3801
+/** Format code for TIFF EP image files */
+#define SUPPORTED_PLAYBACK_FORMAT_TIFF_EP 0x3802
+/** Format code for BMP image files */
+#define SUPPORTED_PLAYBACK_FORMAT_BMP 0x3804
+/** Format code for GIF image files */
+#define SUPPORTED_PLAYBACK_FORMAT_GIF 0x3807
+/** Format code for JFIF image files */
+#define SUPPORTED_PLAYBACK_FORMAT_JFIF 0x3808
+/** Format code for PICT image files */
+#define SUPPORTED_PLAYBACK_FORMAT_PICT 0x380A
+/** Format code for PNG image files */
+#define SUPPORTED_PLAYBACK_FORMAT_PNG 0x380B
+/** Format code for TIFF image files */
+#define SUPPORTED_PLAYBACK_FORMAT_TIFF 0x380D
+/** Format code for JP2 files */
+#define SUPPORTED_PLAYBACK_FORMAT_JP2 0x380F
+/** Format code for JPX files */
+#define SUPPORTED_PLAYBACK_FORMAT_JPX 0x3810
+/** Format code for firmware files */
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED_FIRMWARE 0xB802
+/** Format code for Windows image files */
+#define SUPPORTED_PLAYBACK_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
+/** Format code for undefined audio files files */
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED_AUDIO 0xB900
+/** Format code for WMA audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_WMA 0xB901
+/** Format code for OGG audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_OGG 0xB902
+/** Format code for AAC audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_AAC 0xB903
+/** Format code for Audible audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_AUDIBLE 0xB904
+/** Format code for FLAC audio files */
+#define SUPPORTED_PLAYBACK_FORMAT_FLAC 0xB906
+/** Format code for undefined video files */
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED_VIDEO 0xB980
+/** Format code for WMV video files */
+#define SUPPORTED_PLAYBACK_FORMAT_WMV 0xB981
+/** Format code for MP4 files */
+#define SUPPORTED_PLAYBACK_FORMAT_MP4_CONTAINER 0xB982
+/** Format code for MP2 files */
+#define SUPPORTED_PLAYBACK_FORMAT_MP2 0xB983
+/** Format code for 3GP files */
+#define SUPPORTED_PLAYBACK_FORMAT_3GP_CONTAINER 0xB984
+/** Format code for undefined collections */
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED_COLLECTION 0xBA00
+/** Format code for multimedia albums */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01
+/** Format code for image albums */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_IMAGE_ALBUM 0xBA02
+/** Format code for audio albums */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_AUDIO_ALBUM 0xBA03
+/** Format code for video albums */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_VIDEO_ALBUM 0xBA04
+/** Format code for abstract AV playlists */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_AV_PLAYLIST 0xBA05
+/** Format code for abstract audio playlists */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_AUDIO_PLAYLIST 0xBA09
+/** Format code for abstract video playlists */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_VIDEO_PLAYLIST 0xBA0A
+/** Format code for abstract mediacasts */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_MEDIACAST 0xBA0B
+/** Format code for WPL playlist files */
+#define SUPPORTED_PLAYBACK_FORMAT_WPL_PLAYLIST 0xBA10
+/** Format code for M3u playlist files */
+#define SUPPORTED_PLAYBACK_FORMAT_M3U_PLAYLIST 0xBA11
+/** Format code for MPL playlist files */
+#define SUPPORTED_PLAYBACK_FORMAT_MPL_PLAYLIST 0xBA12
+/** Format code for ASX playlist files */
+#define SUPPORTED_PLAYBACK_FORMAT_ASX_PLAYLIST 0xBA13
+/** Format code for PLS playlist files */
+#define SUPPORTED_PLAYBACK_FORMAT_PLS_PLAYLIST 0xBA14
+/** Format code for undefined document files */
+#define SUPPORTED_PLAYBACK_FORMAT_UNDEFINED_DOCUMENT 0xBA80
+/** Format code for abstract documents */
+#define SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_DOCUMENT 0xBA81
+/** Format code for XML documents */
+#define SUPPORTED_PLAYBACK_FORMAT_XML_DOCUMENT 0xBA82
+/** Format code for MS Word documents */
+#define SUPPORTED_PLAYBACK_FORMAT_MS_WORD_DOCUMENT 0xBA83
+/** Format code for MS Excel spreadsheets */
+#define SUPPORTED_PLAYBACK_FORMAT_MS_EXCEL_SPREADSHEET 0xBA85
+/** Format code for MS PowerPoint presentatiosn */
+#define SUPPORTED_PLAYBACK_FORMAT_MS_POWERPOINT_PRESENTATION 0xBA86
+
+#endif // _MTP_H
diff --git a/mtp/mtp_MtpDatabase.cpp b/mtp/mtp_MtpDatabase.cpp
new file mode 100755
index 0000000..60a871c
--- /dev/null
+++ b/mtp/mtp_MtpDatabase.cpp
@@ -0,0 +1,884 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string>
+#include <map>
+#include <libgen.h>
+#include <cutils/properties.h>
+
+#include "MtpDatabase.h"
+#include "MtpStorage.h"
+#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
+#include "MtpProperty.h"
+#include "MtpDebug.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+#include "mtp.h"
+#include "mtp_MtpDatabase.hpp"
+#include "btree.hpp"
+
+MyMtpDatabase::MyMtpDatabase()
+{
+	storagenum = 0;
+	count = -1;
+}
+
+MyMtpDatabase::~MyMtpDatabase() {
+	std::map<int, MtpStorage*>::iterator i;
+	for (i = storagemap.begin(); i != storagemap.end(); i++) {
+		delete i->second;
+	}
+}
+
+int MyMtpDatabase::FILE_PROPERTIES[10] = {
+	// NOTE must match beginning of AUDIO_PROPERTIES, VIDEO_PROPERTIES
+	// and IMAGE_PROPERTIES below
+	MTP_PROPERTY_STORAGE_ID,
+	MTP_PROPERTY_OBJECT_FORMAT,
+	MTP_PROPERTY_PROTECTION_STATUS,
+	MTP_PROPERTY_OBJECT_SIZE,
+	MTP_PROPERTY_OBJECT_FILE_NAME,
+	MTP_PROPERTY_DATE_MODIFIED,
+	MTP_PROPERTY_PARENT_OBJECT,
+	MTP_PROPERTY_PERSISTENT_UID,
+	MTP_PROPERTY_NAME,
+	MTP_PROPERTY_DATE_ADDED
+};
+int MyMtpDatabase::AUDIO_PROPERTIES[19] = {
+	// NOTE must match FILE_PROPERTIES above
+	MTP_PROPERTY_STORAGE_ID,
+	MTP_PROPERTY_OBJECT_FORMAT,
+	MTP_PROPERTY_PROTECTION_STATUS,
+	MTP_PROPERTY_OBJECT_SIZE,
+	MTP_PROPERTY_OBJECT_FILE_NAME,
+	MTP_PROPERTY_DATE_MODIFIED,
+	MTP_PROPERTY_PARENT_OBJECT,
+	MTP_PROPERTY_PERSISTENT_UID,
+	MTP_PROPERTY_NAME,
+	MTP_PROPERTY_DISPLAY_NAME,
+	MTP_PROPERTY_DATE_ADDED,
+
+	// audio specific properties
+	MTP_PROPERTY_ARTIST,
+	MTP_PROPERTY_ALBUM_NAME,
+	MTP_PROPERTY_ALBUM_ARTIST,
+	MTP_PROPERTY_TRACK,
+	MTP_PROPERTY_ORIGINAL_RELEASE_DATE,
+	MTP_PROPERTY_DURATION,
+	MTP_PROPERTY_GENRE,
+	MTP_PROPERTY_COMPOSER
+};
+
+int MyMtpDatabase::VIDEO_PROPERTIES[15] = {
+	// NOTE must match FILE_PROPERTIES above
+	MTP_PROPERTY_STORAGE_ID,
+	MTP_PROPERTY_OBJECT_FORMAT,
+	MTP_PROPERTY_PROTECTION_STATUS,
+	MTP_PROPERTY_OBJECT_SIZE,
+	MTP_PROPERTY_OBJECT_FILE_NAME,
+	MTP_PROPERTY_DATE_MODIFIED,
+	MTP_PROPERTY_PARENT_OBJECT,
+	MTP_PROPERTY_PERSISTENT_UID,
+	MTP_PROPERTY_NAME,
+	MTP_PROPERTY_DISPLAY_NAME,
+	MTP_PROPERTY_DATE_ADDED,
+
+	// video specific properties
+	MTP_PROPERTY_ARTIST,
+	MTP_PROPERTY_ALBUM_NAME,
+	MTP_PROPERTY_DURATION,
+	MTP_PROPERTY_DESCRIPTION
+};
+
+int MyMtpDatabase::IMAGE_PROPERTIES[12] = {
+	// NOTE must match FILE_PROPERTIES above
+	MTP_PROPERTY_STORAGE_ID,
+	MTP_PROPERTY_OBJECT_FORMAT,
+	MTP_PROPERTY_PROTECTION_STATUS,
+	MTP_PROPERTY_OBJECT_SIZE,
+	MTP_PROPERTY_OBJECT_FILE_NAME,
+	MTP_PROPERTY_DATE_MODIFIED,
+	MTP_PROPERTY_PARENT_OBJECT,
+	MTP_PROPERTY_PERSISTENT_UID,
+	MTP_PROPERTY_NAME,
+	MTP_PROPERTY_DISPLAY_NAME,
+	MTP_PROPERTY_DATE_ADDED,
+
+	// image specific properties
+	MTP_PROPERTY_DESCRIPTION
+};
+
+int MyMtpDatabase::ALL_PROPERTIES[25] = {
+	// NOTE must match FILE_PROPERTIES above
+	MTP_PROPERTY_STORAGE_ID,
+	MTP_PROPERTY_OBJECT_FORMAT,
+	MTP_PROPERTY_PROTECTION_STATUS,
+	MTP_PROPERTY_OBJECT_SIZE,
+	MTP_PROPERTY_OBJECT_FILE_NAME,
+	MTP_PROPERTY_DATE_MODIFIED,
+	MTP_PROPERTY_PARENT_OBJECT,
+	MTP_PROPERTY_PERSISTENT_UID,
+	MTP_PROPERTY_NAME,
+	MTP_PROPERTY_DISPLAY_NAME,
+	MTP_PROPERTY_DATE_ADDED,
+
+	// image specific properties
+	MTP_PROPERTY_DESCRIPTION,
+
+	// audio specific properties
+	MTP_PROPERTY_ARTIST,
+	MTP_PROPERTY_ALBUM_NAME,
+	MTP_PROPERTY_ALBUM_ARTIST,
+	MTP_PROPERTY_TRACK,
+	MTP_PROPERTY_ORIGINAL_RELEASE_DATE,
+	MTP_PROPERTY_DURATION,
+	MTP_PROPERTY_GENRE,
+	MTP_PROPERTY_COMPOSER,
+
+	// video specific properties
+	MTP_PROPERTY_ARTIST,
+	MTP_PROPERTY_ALBUM_NAME,
+	MTP_PROPERTY_DURATION,
+	MTP_PROPERTY_DESCRIPTION,
+
+	// image specific properties
+	MTP_PROPERTY_DESCRIPTION
+};
+
+int MyMtpDatabase::SUPPORTED_PLAYBACK_FORMATS[26] = {
+	SUPPORTED_PLAYBACK_FORMAT_UNDEFINED,
+	SUPPORTED_PLAYBACK_FORMAT_ASSOCIATION,
+	SUPPORTED_PLAYBACK_FORMAT_TEXT,
+	SUPPORTED_PLAYBACK_FORMAT_HTML,
+	SUPPORTED_PLAYBACK_FORMAT_WAV,
+	SUPPORTED_PLAYBACK_FORMAT_MP3,
+	SUPPORTED_PLAYBACK_FORMAT_MPEG,
+	SUPPORTED_PLAYBACK_FORMAT_EXIF_JPEG,
+	SUPPORTED_PLAYBACK_FORMAT_TIFF_EP,
+	SUPPORTED_PLAYBACK_FORMAT_BMP,
+	SUPPORTED_PLAYBACK_FORMAT_GIF,
+	SUPPORTED_PLAYBACK_FORMAT_JFIF,
+	SUPPORTED_PLAYBACK_FORMAT_PNG,
+	SUPPORTED_PLAYBACK_FORMAT_TIFF,
+	SUPPORTED_PLAYBACK_FORMAT_WMA,
+	SUPPORTED_PLAYBACK_FORMAT_OGG,
+	SUPPORTED_PLAYBACK_FORMAT_AAC,
+	SUPPORTED_PLAYBACK_FORMAT_MP4_CONTAINER,
+	SUPPORTED_PLAYBACK_FORMAT_MP2,
+	SUPPORTED_PLAYBACK_FORMAT_3GP_CONTAINER,
+	SUPPORTED_PLAYBACK_FORMAT_ABSTRACT_AV_PLAYLIST,
+	SUPPORTED_PLAYBACK_FORMAT_WPL_PLAYLIST,
+	SUPPORTED_PLAYBACK_FORMAT_M3U_PLAYLIST,
+	SUPPORTED_PLAYBACK_FORMAT_PLS_PLAYLIST,
+	SUPPORTED_PLAYBACK_FORMAT_XML_DOCUMENT,
+	SUPPORTED_PLAYBACK_FORMAT_FLAC
+};
+
+MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
+											MtpObjectFormat format,
+											MtpObjectHandle parent,
+											MtpStorageID storage,
+											uint64_t size,
+											time_t modified) {
+	MTPD("MyMtpDatabase::beginSendObject() which passes to MtpStorage.cpp\n");
+	return storagemap[storage]->beginSendObject(path, format, parent, storage, size, modified);
+}
+
+void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
+								MtpObjectFormat format, bool succeeded) {
+	MTPD("endSendObject() %s\n", path);
+	if (!succeeded) {
+		MTPE("endSendObject() failed, unlinking %s\n", path);
+		unlink(path);
+	}
+}
+
+void MyMtpDatabase::createDB(MtpStorage* storage, MtpStorageID storageID) {
+	storagemap[storageID] = storage;
+	storage->createDB();
+}
+
+MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
+									MtpObjectFormat format,
+									MtpObjectHandle parent) {
+	MTPD("storageID: %d\n", storageID);
+	MtpObjectHandleList* list = new MtpObjectHandleList();
+	list = storagemap[storageID]->getObjectList(storageID, parent);
+	MTPD("list: %d\n", list->size());
+	return list;
+}
+
+int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
+									MtpObjectFormat format,
+									MtpObjectHandle parent) {
+	MTPE("MyMtpDatabase::getNumObjects not implemented, returning 0\n");
+	int result = 0;
+	//get number of objects on filesystem storage
+	return result;
+}
+
+MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
+	// This function tells the host PC which file formats the device supports
+	int* formats;
+	MtpObjectFormatList* list = new MtpObjectFormatList();
+	formats = SUPPORTED_PLAYBACK_FORMATS;
+	int length = sizeof(formats)/ sizeof(int);
+	MTPD("MyMtpDatabase::getSupportedPlaybackFormats length: %i\n", length);
+	for (int i = 0; i < length; i++) {
+		MTPD("supported playback format: %d\n", formats[i]);
+		list->push(formats[i]);
+	}
+	return list;
+}
+
+MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
+	// Android OS implementation of this function returns NULL
+	// so we are not implementing this function either.
+	MTPD("MyMtpDatabase::getSupportedCaptureFormats returning NULL (This is what Android does as well).\n");
+	return NULL;
+}
+
+MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
+	int* properties;
+	MtpObjectPropertyList* list = new MtpObjectPropertyList();
+	properties = FILE_PROPERTIES;
+	int length = sizeof(FILE_PROPERTIES);
+	MTPD("MyMtpDatabase::getSupportedObjectProperties length is: %i, format: %x, sizeof: %i, forcing length to 10\n", length, format, sizeof(properties));
+	for (int i = 0; i < length; i++) {
+		MTPD("supported object property: %x\n", properties[i]);
+		list->push(properties[i]);
+	}
+	return list;
+}
+
+MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
+	int properties[] = {
+		MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,
+		MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,
+		MTP_DEVICE_PROPERTY_IMAGE_SIZE,
+	};
+	MtpDevicePropertyList* list = new MtpDevicePropertyList();
+	int length = sizeof(properties) / sizeof(int);
+	MTPD("MyMtpDatabase::getSupportedDeviceProperties length was: %i, forcing to 3\n", length);
+	length = 3;
+	for (int i = 0; i < length; i++)
+		list->push(properties[i]);
+	return list;
+}
+
+int* MyMtpDatabase::getSupportedObjectProperties(int format) {
+	switch (format) {
+		case MTP_FORMAT_MP3:
+		case MTP_FORMAT_WAV:
+		case MTP_FORMAT_WMA:
+		case MTP_FORMAT_OGG:
+		case MTP_FORMAT_AAC:
+			return AUDIO_PROPERTIES;
+		case MTP_FORMAT_MPEG:
+		case MTP_FORMAT_3GP_CONTAINER:
+		case MTP_FORMAT_WMV:
+			return VIDEO_PROPERTIES;
+		case MTP_FORMAT_EXIF_JPEG:
+		case MTP_FORMAT_GIF:
+		case MTP_FORMAT_PNG:
+		case MTP_FORMAT_BMP:
+			return IMAGE_PROPERTIES;
+		case 0:
+			return ALL_PROPERTIES;
+		default:
+			return FILE_PROPERTIES;
+	}
+}
+
+MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
+											MtpObjectProperty property,
+											MtpDataPacket& packet) {
+	MTPD("MyMtpDatabase::getObjectPropertyValue mtpid: %i, property: %x\n", handle, property);
+	int type;
+	MtpResponseCode result;
+	uint64_t longValue;
+	if (!getObjectPropertyInfo(property, type)) {
+		MTPE("MyMtpDatabase::setObjectPropertyValue returning MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED\n");
+		return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+	}
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		if (storit->second->getObjectPropertyValue(handle, property, longValue) == 0) {
+			result = MTP_RESPONSE_OK;
+			break;
+		}
+	}
+
+	// special case date properties, which are strings to MTP
+	// but stored internally as a uint64
+	if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
+		char date[20];
+		formatDateTime(longValue, date, sizeof(date));
+		packet.putString(date);
+		goto out;
+	}
+	// release date is stored internally as just the year
+	if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
+		char date[20];
+		snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
+		packet.putString(date);
+		goto out;
+	}
+
+	switch (type) {
+		case MTP_TYPE_INT8:
+			packet.putInt8(longValue);
+			break;
+		case MTP_TYPE_UINT8:
+			packet.putUInt8(longValue);
+			break;
+		case MTP_TYPE_INT16:
+			packet.putInt16(longValue);
+			break;
+		case MTP_TYPE_UINT16:
+			packet.putUInt16(longValue);
+			break;
+		case MTP_TYPE_INT32:
+			packet.putInt32(longValue);
+			break;
+		case MTP_TYPE_UINT32:
+			packet.putUInt32(longValue);
+			break;
+		case MTP_TYPE_INT64:
+			packet.putInt64(longValue);
+			break;
+		case MTP_TYPE_UINT64:
+			packet.putUInt64(longValue);
+			break;
+		case MTP_TYPE_INT128:
+			packet.putInt128(longValue);
+			break;
+		case MTP_TYPE_UINT128:
+			packet.putInt128(longValue);
+			break;
+		case MTP_TYPE_STR:
+			{
+				/*std::string stringValue = (string)stringValuesArray[0];
+				if (stringValue) {
+					const char* str = stringValue.c_str();
+					if (str == NULL) {
+						return MTP_RESPONSE_GENERAL_ERROR;
+					}
+					packet.putString(str);
+				} else {
+					packet.putEmptyString();
+				}*/
+				MTPE("STRING unsupported type in getObjectPropertyValue\n");
+				result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+				break;
+			}
+		default:
+			MTPE("unsupported type in getObjectPropertyValue\n");
+			result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+	}
+out:
+	return result;
+}
+
+MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
+											MtpObjectProperty property,
+											MtpDataPacket& packet) {
+	int type;
+	MTPD("MyMtpDatabase::setObjectPropertyValue start\n");
+	if (!getObjectPropertyInfo(property, type)) {
+		MTPE("MyMtpDatabase::setObjectPropertyValue returning MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED\n");
+		return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+	}
+	MTPD("MyMtpDatabase::setObjectPropertyValue continuing\n");
+	long longValue = 0;
+	std::string stringValue;
+
+	switch (type) {
+		case MTP_TYPE_INT8:
+			MTPD("int8\n");
+			longValue = packet.getInt8();
+			break;
+		case MTP_TYPE_UINT8:
+			MTPD("uint8\n");
+			longValue = packet.getUInt8();
+			break;
+		case MTP_TYPE_INT16:
+			MTPD("int16\n");
+			longValue = packet.getInt16();
+			break;
+		case MTP_TYPE_UINT16:
+			MTPD("uint16\n");
+			longValue = packet.getUInt16();
+			break;
+		case MTP_TYPE_INT32:
+			MTPD("int32\n");
+			longValue = packet.getInt32();
+			break;
+		case MTP_TYPE_UINT32:
+			MTPD("uint32\n");
+			longValue = packet.getUInt32();
+			break;
+		case MTP_TYPE_INT64:
+			MTPD("int64\n");
+			longValue = packet.getInt64();
+			break;
+		case MTP_TYPE_UINT64:
+			MTPD("uint64\n");
+			longValue = packet.getUInt64();
+			break;
+		case MTP_TYPE_STR:
+			{
+				MTPD("string\n");
+				MtpStringBuffer buffer;
+				packet.getString(buffer);
+				stringValue = (const char *)buffer;
+				break;
+			 }
+		default:
+			MTPE("MyMtpDatabase::setObjectPropertyValue unsupported type %i in getObjectPropertyValue\n", type);
+			return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+	}
+
+	int result = MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+
+	switch (property) {
+		case MTP_PROPERTY_OBJECT_FILE_NAME:
+			{
+				MTPD("MyMtpDatabase::setObjectPropertyValue renaming file, handle: %d, new name: '%s'\n", handle, stringValue.c_str());
+				std::map<int, MtpStorage*>::iterator storit;
+				for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+					if (storit->second->renameObject(handle, stringValue) == 0) {
+						MTPD("MTP_RESPONSE_OK\n");
+						result = MTP_RESPONSE_OK;
+						break;
+					}
+				}
+			}
+			break;
+
+		default:
+			MTPE("MyMtpDatabase::setObjectPropertyValue property %x not supported.\n", property);
+			result = MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
+	}
+	MTPD("MyMtpDatabase::setObjectPropertyValue returning %d\n", result);
+	return result;
+}
+
+MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
+											MtpDataPacket& packet) {
+	int type, result = 0;
+	char prop_value[PROPERTY_VALUE_MAX];
+	MTPD("property %s\n",
+			MtpDebug::getDevicePropCodeName(property));
+	if (!getDevicePropertyInfo(property, type)) {
+		MTPE("MyMtpDatabase::getDevicePropertyValue MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED\n");
+		return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
+	}
+	MTPD("property %s\n",
+			MtpDebug::getDevicePropCodeName(property));
+	MTPD("property %x\n", property);
+	MTPD("MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME %x\n", MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME); 
+	switch (property) {
+		case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
+		case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
+			result =  MTP_RESPONSE_OK;
+			break;
+		default:
+		{
+			MTPE("MyMtpDatabase::getDevicePropertyValue property %x not supported\n", property);
+			result = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
+			break;
+		}
+	}
+
+	if (result != MTP_RESPONSE_OK) {
+		MTPD("MTP_REPONSE_OK NOT OK\n");
+		return result;
+	}
+
+	long longValue = 0;
+	property_get("ro.build.product", prop_value, "unknown manufacturer");
+	switch (type) {
+		case MTP_TYPE_INT8: {
+			MTPD("MTP_TYPE_INT8\n");
+			packet.putInt8(longValue);
+			break;
+		}
+		case MTP_TYPE_UINT8:
+		{
+			MTPD("MTP_TYPE_UINT8\n");
+			packet.putUInt8(longValue);
+			break;
+		}
+		case MTP_TYPE_INT16:
+		{
+			MTPD("MTP_TYPE_INT16\n");
+			packet.putInt16(longValue);
+			break;
+		}
+		case MTP_TYPE_UINT16:
+		{
+			MTPD("MTP_TYPE_UINT16\n");
+			packet.putUInt16(longValue);
+			break;
+		}
+		case MTP_TYPE_INT32:
+		{
+			MTPD("MTP_TYPE_INT32\n");
+			packet.putInt32(longValue);
+			break;
+		}
+		case MTP_TYPE_UINT32:
+		{
+			MTPD("MTP_TYPE_UINT32\n");
+			packet.putUInt32(longValue);
+			break;
+		}
+		case MTP_TYPE_INT64:
+		{
+			MTPD("MTP_TYPE_INT64\n");
+			packet.putInt64(longValue);
+			break;
+		}
+		case MTP_TYPE_UINT64:
+		{
+			MTPD("MTP_TYPE_UINT64\n");
+			packet.putUInt64(longValue);
+			break;
+		}
+		case MTP_TYPE_INT128:
+		{
+			MTPD("MTP_TYPE_INT128\n");
+			packet.putInt128(longValue);
+			break;
+		}
+		case MTP_TYPE_UINT128:
+		{
+			MTPD("MTP_TYPE_UINT128\n");
+			packet.putInt128(longValue);
+			break;
+		}
+		case MTP_TYPE_STR:
+		{
+			MTPD("MTP_TYPE_STR\n");
+			char* str = prop_value;
+			packet.putString(str);
+			break;
+		 }
+		default:
+			MTPE("MyMtpDatabase::getDevicePropertyValue unsupported type %i in getDevicePropertyValue\n", type);
+			return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
+	}
+
+	return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) {
+   	int type;
+	MTPE("MyMtpDatabase::setDevicePropertyValue not implemented, returning 0\n");
+	return 0;
+}
+
+MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
+	MTPE("MyMtpDatabase::resetDeviceProperty not implemented, returning -1\n");
+   	return -1;
+}
+
+MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) {
+	MTPD("getObjectPropertyList()\n");
+	MTPD("property: %x\n", property);
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		MTPD("MyMtpDatabase::getObjectPropertyList calling getObjectPropertyList\n");
+		if (storit->second->getObjectPropertyList(handle, format, property, groupCode, depth, packet) == 0) {
+			MTPD("MTP_RESPONSE_OK\n");
+   			return MTP_RESPONSE_OK;
+		}
+	}
+	MTPE("MyMtpDatabase::getObjectPropertyList MTP_RESPOSNE_INVALID_OBJECT_HANDLE %i\n", handle);
+	return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+}
+
+MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		if (storit->second->getObjectInfo(handle, info) == 0) {
+			MTPD("MTP_RESPONSE_OK\n");
+			return MTP_RESPONSE_OK;
+		}
+	}
+	MTPE("MyMtpDatabase::getObjectInfo MTP_RESPONSE_INVALID_OBJECT_HANDLE %i\n", handle);
+	return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+}
+
+void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
+	MtpString path;
+	int64_t length;
+	MtpObjectFormat format;
+	void* result = NULL;
+	outThumbSize = 0;
+	MTPE("MyMtpDatabase::getThumbnail not implemented, returning 0\n");
+	return 0;
+}
+
+MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) {
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		MTPD("MyMtpDatabase::getObjectFilePath calling getObhectFilePath\n");
+		if (storit->second->getObjectFilePath(handle, outFilePath, outFileLength, outFormat) == 0) {
+			MTPD("MTP_RESPONSE_OK\n");
+			return MTP_RESPONSE_OK;
+		}
+	}
+	MTPE("MyMtpDatabase::getObjectFilePath MTP_RESPOSNE_INVALID_OBJECT_HANDLE %i\n", handle);
+	return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+}
+
+MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
+	MTPD("deleteFile\n");
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		if (storit->second->deleteFile(handle) == 0) {
+			MTPD("MTP_RESPONSE_OK\n");
+			return MTP_RESPONSE_OK;
+		}
+	}
+	MTPE("MyMtpDatabase::deleteFile MTP_RESPONSE_INVALID_OBJECT_HANDLE %i\n", handle);
+	return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+}
+
+struct PropertyTableEntry {
+	MtpObjectProperty   property;
+	int				 type;
+};
+
+static const PropertyTableEntry   kObjectPropertyTable[] = {
+	{   MTP_PROPERTY_STORAGE_ID,		MTP_TYPE_UINT32	 },
+	{   MTP_PROPERTY_OBJECT_FORMAT,	 MTP_TYPE_UINT16	 },
+	{   MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16	 },
+	{   MTP_PROPERTY_OBJECT_SIZE,	   MTP_TYPE_UINT64	 },
+	{   MTP_PROPERTY_OBJECT_FILE_NAME,  MTP_TYPE_STR		},
+	{   MTP_PROPERTY_DATE_MODIFIED,	 MTP_TYPE_STR		},
+	{   MTP_PROPERTY_PARENT_OBJECT,	 MTP_TYPE_UINT32	 },
+	{   MTP_PROPERTY_PERSISTENT_UID,	MTP_TYPE_UINT128	},
+	{   MTP_PROPERTY_NAME,			  MTP_TYPE_STR		},
+	{   MTP_PROPERTY_DISPLAY_NAME,	  MTP_TYPE_STR		},
+	{   MTP_PROPERTY_DATE_ADDED,		MTP_TYPE_STR		},
+	{   MTP_PROPERTY_ARTIST,			MTP_TYPE_STR		},
+	{   MTP_PROPERTY_ALBUM_NAME,		MTP_TYPE_STR		},
+	{   MTP_PROPERTY_ALBUM_ARTIST,	  MTP_TYPE_STR		},
+	{   MTP_PROPERTY_TRACK,			 MTP_TYPE_UINT16	 },
+	{   MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR	},
+	{   MTP_PROPERTY_GENRE,			 MTP_TYPE_STR		},
+	{   MTP_PROPERTY_COMPOSER,		  MTP_TYPE_STR		},
+	{   MTP_PROPERTY_DURATION,		  MTP_TYPE_UINT32	 },
+	{   MTP_PROPERTY_DESCRIPTION,	   MTP_TYPE_STR		},
+};
+
+static const PropertyTableEntry   kDevicePropertyTable[] = {
+	{   MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,	MTP_TYPE_STR },
+	{   MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,	   MTP_TYPE_STR },
+	{   MTP_DEVICE_PROPERTY_IMAGE_SIZE,				 MTP_TYPE_STR },
+};
+
+bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
+	int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
+	const PropertyTableEntry* entry = kObjectPropertyTable;
+	MTPD("MyMtpDatabase::getObjectPropertyInfo size is: %i\n", count);
+	for (int i = 0; i < count; i++, entry++) {
+		if (entry->property == property) {
+			type = entry->type;
+			return true;
+		}
+	}
+	return false;
+}
+
+bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
+	int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
+	const PropertyTableEntry* entry = kDevicePropertyTable;
+	MTPD("MyMtpDatabase::getDevicePropertyInfo count is: %i\n", count);
+	for (int i = 0; i < count; i++, entry++) {
+		if (entry->property == property) {
+			type = entry->type;
+			MTPD("type: %x\n", type);
+			return true;
+		}
+	}
+	return false;
+}
+
+MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
+	// call function and place files with associated handles into int array
+	MTPD("MyMtpDatabase::getObjectReferences returning null, this seems to be what Android always does.\n");
+	MTPD("handle: %d\n", handle);
+	// Windows + Android seems to always return a NULL in this function, c == null path
+	// The way that this is handled in Android then is to do this:
+	return NULL;
+}
+
+MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
+													MtpObjectHandleList* references) {
+	int count = references->size();
+	MTPE("MyMtpDatabase::setObjectReferences not implemented, returning 0\n");
+	return 0;
+}
+
+MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
+											MtpObjectFormat format) {
+	MTPD("MyMtpDatabase::getObjectPropertyDesc start\n");
+	MtpProperty* result = NULL;
+	switch (property) {
+		case MTP_PROPERTY_OBJECT_FORMAT:
+			// use format as default value
+			MTPD("MyMtpDatabase::getObjectPropertyDesc format\n");
+			result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
+			break;
+		case MTP_PROPERTY_PROTECTION_STATUS:
+		case MTP_PROPERTY_TRACK:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc track\n");
+			result = new MtpProperty(property, MTP_TYPE_UINT16);
+			break;
+		case MTP_PROPERTY_STORAGE_ID:
+		case MTP_PROPERTY_PARENT_OBJECT:
+		case MTP_PROPERTY_DURATION:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc duration\n");
+			result = new MtpProperty(property, MTP_TYPE_UINT32);
+			break;
+		case MTP_PROPERTY_OBJECT_SIZE:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc size\n");
+			result = new MtpProperty(property, MTP_TYPE_UINT64);
+			break;
+		case MTP_PROPERTY_PERSISTENT_UID:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc persistent uid\n");
+			result = new MtpProperty(property, MTP_TYPE_UINT128);
+			break;
+		case MTP_PROPERTY_NAME:
+		case MTP_PROPERTY_DISPLAY_NAME:
+		case MTP_PROPERTY_ARTIST:
+		case MTP_PROPERTY_ALBUM_NAME:
+		case MTP_PROPERTY_ALBUM_ARTIST:
+		case MTP_PROPERTY_GENRE:
+		case MTP_PROPERTY_COMPOSER:
+		case MTP_PROPERTY_DESCRIPTION:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc description\n");
+			result = new MtpProperty(property, MTP_TYPE_STR);
+			break;
+		case MTP_PROPERTY_DATE_MODIFIED:
+		case MTP_PROPERTY_DATE_ADDED:
+		case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc date\n");
+			result = new MtpProperty(property, MTP_TYPE_STR);
+			result->setFormDateTime();
+			break;
+		case MTP_PROPERTY_OBJECT_FILE_NAME:
+			MTPD("MyMtpDatabase::getObjectPropertyDesc file name\n");
+			// We allow renaming files and folders
+			result = new MtpProperty(property, MTP_TYPE_STR, true);
+			break;
+	}
+	return result;
+}
+
+MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
+	MtpProperty* result = NULL;
+	int ret;
+	bool writable = true;
+	switch (property) {
+		case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
+		case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
+			ret = MTP_RESPONSE_OK;
+			// fall through
+		case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
+			result = new MtpProperty(property, MTP_TYPE_STR, writable);
+			ret = MTP_RESPONSE_OK;
+
+			// get current value
+			if (ret == MTP_RESPONSE_OK) {
+				MTPD("here\n");
+				result->setCurrentValue('\0');
+				result->setDefaultValue('\0');
+			} else {
+				MTPE("unable to read device property, response: %04X", ret);
+			}
+			break;
+		default:
+			ret = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
+			break;
+		}
+
+	return result;
+}
+
+void MyMtpDatabase::sessionStarted() {
+	MTPD("MyMtpDatabase::sessionStarted not implemented or does nothing, returning\n");
+	return;
+}
+
+void MyMtpDatabase::sessionEnded() {
+	MTPD("MyMtpDatabase::sessionEnded not implemented or does nothing, returning\n");
+	return;
+}
+
+// ----------------------------------------------------------------------------
+
+static void
+android_mtp_MtpDatabase_setup()
+{
+	MyMtpDatabase* database = new MyMtpDatabase();
+}
+
+static void
+android_mtp_MtpDatabase_finalize()
+{
+	return;
+}
+
+static std::string
+android_mtp_MtpPropertyGroup_format_date_time(long seconds)
+{
+	char date[20];
+	formatDateTime(seconds, date, sizeof(date));
+	return date;
+}
+
+void MyMtpDatabase::lockMutex(void) {
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		storit->second->lockMutex(0);
+	}
+}
+
+void MyMtpDatabase::unlockMutex(void) {
+	std::map<int, MtpStorage*>::iterator storit;
+	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
+		storit->second->unlockMutex(0);
+	}
+}
diff --git a/mtp/mtp_MtpDatabase.hpp b/mtp/mtp_MtpDatabase.hpp
new file mode 100755
index 0000000..2f5e931
--- /dev/null
+++ b/mtp/mtp_MtpDatabase.hpp
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef MTP_MTPDATABASE_HPP
+#define MTP_MTPDATABASE_HPP
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <map>
+#include <string>
+#include <deque>
+
+#include "MtpDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
+#include "MtpProperty.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+#include "mtp.h"
+
+class MyMtpDatabase : public MtpDatabase {
+private:
+	int* getSupportedObjectProperties(int format);
+
+    static int FILE_PROPERTIES[10];
+    static int AUDIO_PROPERTIES[19];
+    static int VIDEO_PROPERTIES[15];
+    static int IMAGE_PROPERTIES[12];
+    static int ALL_PROPERTIES[25];
+    static int SUPPORTED_PLAYBACK_FORMATS[26];
+	int storagenum;
+	int count;
+	std::string lastfile;
+	std::map<int, MtpStorage*> storagemap;
+	void countDirs(std::string path);
+	int readParentDirs(std::string path, int storageID);
+
+public:
+                                    MyMtpDatabase();
+    virtual                         ~MyMtpDatabase();
+
+	void					createDB(MtpStorage* storage, MtpStorageID storageID);
+    virtual MtpObjectHandle         beginSendObject(const char* path,
+                                            MtpObjectFormat format,
+                                            MtpObjectHandle parent,
+                                            MtpStorageID storage,
+                                            uint64_t size,
+                                            time_t modified);
+
+    virtual void                    endSendObject(const char* path,
+                                            MtpObjectHandle handle,
+                                            MtpObjectFormat format,
+                                            bool succeeded);
+
+    virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
+                                    MtpObjectFormat format,
+                                    MtpObjectHandle parent);
+
+    virtual int                     getNumObjects(MtpStorageID storageID,
+                                            MtpObjectFormat format,
+                                            MtpObjectHandle parent);
+
+    // callee should delete[] the results from these
+    // results can be NULL
+    virtual MtpObjectFormatList*    getSupportedPlaybackFormats();
+    virtual MtpObjectFormatList*    getSupportedCaptureFormats();
+    virtual MtpObjectPropertyList*  getSupportedObjectProperties(MtpObjectFormat format);
+    virtual MtpDevicePropertyList*  getSupportedDeviceProperties();
+
+    virtual MtpResponseCode         getObjectPropertyValue(MtpObjectHandle handle,
+                                            MtpObjectProperty property,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         setObjectPropertyValue(MtpObjectHandle handle,
+                                            MtpObjectProperty property,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         getDevicePropertyValue(MtpDeviceProperty property,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         setDevicePropertyValue(MtpDeviceProperty property,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         resetDeviceProperty(MtpDeviceProperty property);
+
+    virtual MtpResponseCode         getObjectPropertyList(MtpObjectHandle handle,
+                                            uint32_t format, uint32_t property,
+                                            int groupCode, int depth,
+                                            MtpDataPacket& packet);
+
+    virtual MtpResponseCode         getObjectInfo(MtpObjectHandle handle,
+                                            MtpObjectInfo& info);
+
+    virtual void*                   getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
+
+    virtual MtpResponseCode         getObjectFilePath(MtpObjectHandle handle,
+                                            MtpString& outFilePath,
+                                            int64_t& outFileLength,
+                                            MtpObjectFormat& outFormat);
+    virtual MtpResponseCode         deleteFile(MtpObjectHandle handle);
+
+    bool                            getObjectPropertyInfo(MtpObjectProperty property, int& type);
+    bool                            getDevicePropertyInfo(MtpDeviceProperty property, int& type);
+
+    virtual MtpObjectHandleList*    getObjectReferences(MtpObjectHandle handle);
+
+    virtual MtpResponseCode         setObjectReferences(MtpObjectHandle handle,
+                                            MtpObjectHandleList* references);
+
+    virtual MtpProperty*            getObjectPropertyDesc(MtpObjectProperty property,
+                                            MtpObjectFormat format);
+
+    virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property);
+
+    virtual void                    sessionStarted();
+
+    virtual void                    sessionEnded();
+    virtual void                    lockMutex();
+    virtual void                    unlockMutex();
+};
+#endif
diff --git a/mtp/mtp_MtpServer.cpp b/mtp/mtp_MtpServer.cpp
new file mode 100755
index 0000000..8565d54
--- /dev/null
+++ b/mtp/mtp_MtpServer.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <vector>
+#include <utils/threads.h>
+
+#include "mtp_MtpServer.hpp"
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "MtpDebug.h"
+
+#include <string>
+
+void twmtp_MtpServer::start()
+{
+	setup();
+	add_storage();
+	server->run();
+}
+
+void twmtp_MtpServer::set_storages(storages* mtpstorages) {
+	stores = mtpstorages;
+}
+
+void twmtp_MtpServer::setup()
+{
+	#define USB_MTP_DEVICE "/dev/mtp_usb"
+	usePtp =  false;
+	MyMtpDatabase* mtpdb = new MyMtpDatabase();
+#ifdef USB_MTP_DEVICE
+	int fd = open(USB_MTP_DEVICE, O_RDWR);
+#else
+	int fd = open("/dev/mtp_usb", O_RDWR);
+#endif
+	if (fd >= 0) {
+		MTPD("fd: %d\n", fd);
+		server = new MtpServer(fd, mtpdb, usePtp, 0, 0664, 0775);
+		refserver = server;
+		MTPI("created new mtpserver object\n");
+	} else {
+		MTPE("could not open MTP driver, errno: %d", errno);
+	}
+}
+
+void twmtp_MtpServer::run()
+{
+	MTPD("running in twmtp\n");
+	server->run();
+}
+
+void twmtp_MtpServer::cleanup()
+{
+	android::Mutex sMutex;
+	android::Mutex::Autolock autoLock(sMutex);
+
+	if (server) {
+		delete server;
+	} else {
+		MTPD("server is null in cleanup");
+	}
+}
+
+void twmtp_MtpServer::send_object_added(int handle)
+{
+	android::Mutex sMutex;
+	android::Mutex::Autolock autoLock(sMutex);
+
+	if (server)
+		server->sendObjectAdded(handle);
+	else
+		MTPD("server is null in send_object_added");
+}
+
+void twmtp_MtpServer::send_object_removed(int handle)
+{
+	android::Mutex sMutex;
+	android::Mutex::Autolock autoLock(sMutex);
+
+	if (server)
+		server->sendObjectRemoved(handle);
+	else
+		MTPD("server is null in send_object_removed");
+}
+
+void twmtp_MtpServer::add_storage()
+{
+	android::Mutex sMutex;
+	android::Mutex::Autolock autoLock(sMutex);
+
+	MTPI("adding internal storage\n");
+	for (unsigned int i = 0; i < stores->size(); ++i) {
+			std::string pathStr = stores->at(i)->mount;
+
+			if (!pathStr.empty()) {
+				std::string descriptionStr = stores->at(i)->display;
+				int storageID = stores->at(i)->mtpid;
+				long reserveSpace = 1;
+				bool removable = false;
+				long maxFileSize = 1000000000L;
+				if (descriptionStr != "") {
+					MtpStorage* storage = new MtpStorage(storageID, &pathStr[0], &descriptionStr[0], reserveSpace, removable, maxFileSize, refserver);
+					server->addStorage(storage);
+				}
+		}
+	}
+}
+
+void twmtp_MtpServer::remove_storage(int storageId)
+{
+	android::Mutex sMutex;
+	android::Mutex::Autolock autoLock(sMutex);
+
+	if (server) {
+		MtpStorage* storage = server->getStorage(storageId);
+		if (storage) {
+			server->removeStorage(storage);
+			delete storage;
+		}
+	} else
+		MTPD("server is null in remove_storage");
+}
diff --git a/mtp/mtp_MtpServer.hpp b/mtp/mtp_MtpServer.hpp
new file mode 100755
index 0000000..360d1c3
--- /dev/null
+++ b/mtp/mtp_MtpServer.hpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef MTP_MTPSERVER_HPP
+#define MTP_MTPSERVER_HPP
+#include <utils/Log.h>
+
+#include <string>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utils/threads.h>
+
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "mtp_MtpDatabase.hpp"
+
+typedef struct Storage {
+	std::string display;
+	std::string mount;
+	int mtpid;
+} storage;
+
+typedef std::vector<storage*> storages;
+
+class twmtp_MtpServer {
+	public:
+		void start();
+		void setup();
+		void run();
+		void cleanup();
+		void send_object_added(int handle);
+		void send_object_removed(int handle);
+		void add_storage();
+		void remove_storage(int storageId);
+		void set_storages(storages* mtpstorages);
+		storages *stores;
+	private:
+		bool usePtp;
+		MtpServer* server;
+		MtpServer* refserver;
+
+};
+#endif
diff --git a/mtp/node.cpp b/mtp/node.cpp
new file mode 100755
index 0000000..a9c1f9b
--- /dev/null
+++ b/mtp/node.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ * 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 <iostream>
+#include <vector>
+#include <sstream>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include "btree.hpp"
+#include "mtp.h"
+#include "MtpDebug.h"
+
+
+Node::Node() {
+	mtpid= -1;
+	path = "";
+	left = NULL;
+	right = NULL;
+	parent = NULL;
+	mtpparentid = 0;
+}
+
+void Node::setMtpid(int aMtpid) { mtpid = aMtpid; }
+void Node::setPath(std::string aPath) { path = aPath; }
+void Node::setLeft(Node* aLeft) { left = aLeft; }
+void Node::setRight(Node* aRight) { right = aRight; }
+void Node::setParent(Node* aParent) { parent = aParent; }
+void Node::setMtpParentId(int id) {
+	mtpparentid = id;
+	MTPD("setting mtpparentid: %i on mtpid: %i\n", mtpparentid, mtpid);
+}
+int Node::Mtpid() { return mtpid; }
+int Node::getMtpParentId() { return mtpparentid; }
+std::string Node::getPath() { return path; }
+Node* Node::Left() { return left; }
+Node* Node::Right() { return right; }
+Node* Node::Parent() { return parent; }
+
+uint64_t Node::getIntProperty(uint64_t property) {
+	for (unsigned index = 0; index < mtpProp.size(); ++index) {
+		if (mtpProp[index].property == property)
+			return mtpProp[index].valueInt;
+	}
+	MTPE("Node::getIntProperty failed to find property %x, returning -1\n", (unsigned)property);
+	return -1;
+}
+
+void Node::addProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType) {
+	MTPD("adding str property: %lld, valueInt: %lld, valueStr: %s, dataType: %d\n", property, valueInt, valueStr.c_str(), dataType);
+	struct mtpProperty prop;
+	prop.property = property;
+	prop.valueInt = valueInt;
+	prop.valueStr = valueStr;
+	prop.dataType = dataType;
+	mtpProp.push_back(prop);
+}
+
+void Node::updateProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType) {
+	for (unsigned i = 0; i < mtpProp.size(); i++) {
+		if (mtpProp[i].property == property) {
+			mtpProp[i].valueInt = valueInt;
+			mtpProp[i].valueStr = valueStr;
+			mtpProp[i].dataType = dataType;
+			return;
+		}
+	}
+	addProperty(property, valueInt, valueStr, dataType);
+}
+
+std::vector<Node::mtpProperty>& Node::getMtpProps() {
+	return mtpProp;
+}
+
+void Node::addProperties(int storageID, int parent_object) {
+	struct stat st;
+	int mFormat = 0;
+	uint64_t puid;
+
+	std::string mtpidStr = static_cast<std::ostringstream*>( &(std::ostringstream() << mtpid) )->str();
+	std::string storageIDStr = static_cast<std::ostringstream*>( &(std::ostringstream() << storageID) )->str();
+	std::string puidStr = storageIDStr + mtpidStr;
+	if ( ! (std::istringstream(puidStr) >> puid) ) puid = 0;
+	stat(getPath().c_str(), &st);
+	std::string mtimeStr = static_cast<std::ostringstream*>( &(std::ostringstream() << st.st_mtime) )->str();
+	std::string atimeStr = static_cast<std::ostringstream*>( &(std::ostringstream() << st.st_atime) )->str();
+	if (S_ISDIR(st.st_mode)) {
+		mFormat = MTP_FORMAT_ASSOCIATION; // folder
+	}
+	else {
+		mFormat = MTP_FORMAT_UNDEFINED;   // file
+	}
+	addProperty(MTP_PROPERTY_STORAGE_ID, storageID, "", MTP_TYPE_UINT32);
+	addProperty(MTP_PROPERTY_OBJECT_FORMAT, mFormat, "", MTP_TYPE_UINT16);
+	addProperty(MTP_PROPERTY_PROTECTION_STATUS, 0, "", MTP_TYPE_UINT16);
+	addProperty(MTP_PROPERTY_OBJECT_SIZE, st.st_size, "", MTP_TYPE_UINT64);
+	addProperty(MTP_PROPERTY_OBJECT_FILE_NAME, 0, basename(getPath().c_str()), MTP_TYPE_STR);
+	MTPD("mtpid: %i, filename: '%s', parent object: %i\n", mtpid, basename(getPath().c_str()), parent_object);
+	addProperty(MTP_PROPERTY_DATE_MODIFIED, 0, mtimeStr, MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_PARENT_OBJECT, parent_object, "", MTP_TYPE_UINT32);
+	addProperty(MTP_PROPERTY_PERSISTENT_UID, puid, "", MTP_TYPE_UINT128);
+	addProperty(MTP_PROPERTY_NAME, 0, basename(getPath().c_str()), MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_DISPLAY_NAME, 0, basename(getPath().c_str()), MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_DATE_ADDED, 0, atimeStr, MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_DESCRIPTION, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_ARTIST, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_ALBUM_NAME, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_ALBUM_ARTIST, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_TRACK, 0, "", MTP_TYPE_UINT16);
+	addProperty(MTP_PROPERTY_ORIGINAL_RELEASE_DATE, 0, "00101T000000", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_DURATION, 0, "", MTP_TYPE_UINT32);
+	addProperty(MTP_PROPERTY_GENRE, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_COMPOSER, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_ARTIST, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_ALBUM_NAME, 0, "", MTP_TYPE_STR);
+	addProperty(MTP_PROPERTY_DURATION, 0, "", MTP_TYPE_UINT32);
+	addProperty(MTP_PROPERTY_DESCRIPTION, 0, "", MTP_TYPE_STR);
+}
diff --git a/mtp/twrpMtp.cpp b/mtp/twrpMtp.cpp
new file mode 100755
index 0000000..ff58f79
--- /dev/null
+++ b/mtp/twrpMtp.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ * 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 <string>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include "MtpTypes.h"
+#include "MtpPacket.h"
+#include "MtpDataPacket.h"
+#include "MtpDatabase.h"
+#include "MtpRequestPacket.h"
+#include "MtpResponsePacket.h"
+#include "mtp_MtpDatabase.hpp"
+#include "mtp_MtpServer.hpp"
+#include "twrpMtp.hpp"
+#include "MtpDebug.h"
+
+#ifdef TWRPMTP
+static void usage(std::string prg) {
+	printf("Usage: %s <OPTIONS>\n", prg.c_str());
+	printf("Options:\n");
+	printf("\t-h, --help\t\tShow Usage\n");
+	printf("\t-s1, --storage1 /path/to/dir\t\tDestination to first storage directory\n");
+	printf("\t-s2, --storage2 /path/to/dir\t\tDestination to first storage directory\n");
+	printf("\t-sN, --storageN /path/to/dir\t\tDestination to first storage directory\n");
+}
+
+int main(int argc, char* argv[]) {
+	printf("argc: %d\n", argc);
+	if (argc < 2) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	std::vector <std::string> storages;
+
+	for (int i = 1; i < argc; ++i) {
+		std::string arg = argv[i];
+		if ((arg == "-h") || (arg == "--help")) {
+			usage(argv[0]);
+		}
+		else {
+			storages.push_back(arg);
+		}
+	}
+	printf("starting\n");
+	twmtp_MtpServer* mtp = new twmtp_MtpServer();
+	mtp->set_storages(storages);
+	mtp->start();
+	return 0;
+}
+#endif //def TWRPMTP
+
+twrpMtp::twrpMtp() {
+	mtpstorages = new storages;
+}
+
+int twrpMtp::start(void) {
+	MTPI("Starting MTP\n");
+	twmtp_MtpServer *mtp = new twmtp_MtpServer();
+	mtp->set_storages(mtpstorages);
+	mtp->start();
+	return 0;
+}
+
+pthread_t twrpMtp::runserver(void) {
+	pthread_t thread;
+	ThreadPtr mtpptr = &twrpMtp::start;
+	PThreadPtr p = *(PThreadPtr*)&mtpptr;
+	pthread_create(&thread, NULL, p, this);
+	return thread;
+}
+
+void twrpMtp::addStorage(std::string display, std::string path, int mtpid) {
+	s = new storage;
+	s->display = display;
+	s->mount = path;
+	s->mtpid = mtpid;
+	MTPD("twrpMtp mtpid: %d\n", s->mtpid);
+	mtpstorages->push_back(s);
+}
diff --git a/mtp/twrpMtp.hpp b/mtp/twrpMtp.hpp
new file mode 100755
index 0000000..2dd56a2
--- /dev/null
+++ b/mtp/twrpMtp.hpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ *
+ * 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 TWRPMTP_HPP
+#define TWRPMTP_HPP
+
+#include <fcntl.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <string>
+#include <vector>
+#include <pthread.h>
+#include "MtpTypes.h"
+#include "MtpPacket.h"
+#include "MtpDataPacket.h"
+#include "MtpDatabase.h"
+#include "MtpRequestPacket.h"
+#include "MtpResponsePacket.h"
+#include "mtp_MtpDatabase.hpp"
+
+class twrpMtp {
+	public:
+		twrpMtp();
+		pthread_t runserver(void);
+		void addStorage(std::string display, std::string path, int mtpid);
+	private:
+		int start(void);
+		typedef int (twrpMtp::*ThreadPtr)(void);
+		typedef void* (*PThreadPtr)(void *);
+		storages *mtpstorages;
+		storage *s;
+};
+#endif
diff --git a/partition.cpp b/partition.cpp
index 1a62bba..f1d7fd2 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -107,7 +107,8 @@
 	{ 0,            0 },
 };
 
-TWPartition::TWPartition(void) {
+TWPartition::TWPartition(int *id) {
+	initmtpid = id;
 	Can_Be_Mounted = false;
 	Can_Be_Wiped = false;
 	Can_Be_Backed_Up = false;
@@ -430,6 +431,12 @@
 		}
 	}
 
+	// Generate MTP ID
+	if (Is_Storage) {
+		(*initmtpid)++;
+		mtpid = *initmtpid;
+	}
+
 	// Process any custom flags
 	if (Flags.size() > 0)
 		Process_Flags(Flags, Display_Error);
@@ -1051,6 +1058,9 @@
 		if (never_unmount_system == 1 && Mount_Point == "/system")
 			return true; // Never unmount system if you're not supposed to unmount it
 
+		if (Is_Storage)
+			TWFunc::Toggle_MTP(false);
+
 #ifdef TW_INCLUDE_CRYPTO_SAMSUNG
 		if (EcryptFS_Password.size() > 0) {
 			if (unmount_ecryptfs_drive(Mount_Point.c_str()) != 0) {
@@ -1074,15 +1084,16 @@
 			else
 				LOGINFO("Unable to unmount '%s'\n", Mount_Point.c_str());
 			return false;
-		} else
+		} else {
 			return true;
+		}
 	} else {
 		return true;
 	}
 }
 
 bool TWPartition::Wipe(string New_File_System) {
-	bool wiped = false, update_crypt = false, recreate_media = true;
+	bool wiped = false, update_crypt = false, recreate_media = true, mtp_toggle = true;
 	int check;
 	string Layout_Filename = Mount_Point + "/.layout_version";
 
@@ -1109,8 +1120,8 @@
 	if (Has_Data_Media && Current_File_System == New_File_System) {
 		wiped = Wipe_Data_Without_Wiping_Media();
 		recreate_media = false;
+		mtp_toggle = false;
 	} else {
-
 		DataManager::GetValue(TW_RM_RF_VAR, check);
 
 		if (check || Use_Rm_Rf)
@@ -1128,6 +1139,9 @@
 		else if (New_File_System == "f2fs")
 			wiped = Wipe_F2FS();
 		else {
+			if (Is_Storage) {
+				TWFunc::Toggle_MTP(true);
+			}
 			LOGERR("Unable to wipe '%s' -- unknown file system '%s'\n", Mount_Point.c_str(), New_File_System.c_str());
 			unlink("/.layout_version");
 			return false;
@@ -1169,6 +1183,9 @@
 			Recreate_Media_Folder();
 		}
 	}
+	if (Is_Storage && mtp_toggle) {
+		TWFunc::Toggle_MTP(true);
+	}
 	return wiped;
 }
 
@@ -1417,6 +1434,8 @@
 	Decrypted_Block_Device = "";
 	Is_Decrypted = false;
 	Is_Encrypted = false;
+	Find_Actual_Block_Device();
+	bool mtp_was_enabled = TWFunc::Toggle_MTP(false);
 	if (Wipe(Fstab_File_System)) {
 		Has_Data_Media = Save_Data_Media;
 		if (Has_Data_Media && !Symlink_Mount_Point.empty()) {
@@ -1425,6 +1444,7 @@
 #ifndef TW_OEM_BUILD
 		gui_print("You may need to reboot recovery to be able to use /data again.\n");
 #endif
+		TWFunc::Toggle_MTP(mtp_was_enabled);
 		return true;
 	} else {
 		Has_Data_Media = Save_Data_Media;
@@ -1632,6 +1652,8 @@
 }
 
 bool TWPartition::Wipe_RMRF() {
+	if (Is_Storage)
+		TWFunc::Toggle_MTP(false);
 	if (!Mount(true))
 		return false;
 
@@ -2018,9 +2040,9 @@
 }
 
 void TWPartition::Find_Actual_Block_Device(void) {
-	if (Is_Decrypted) {
+	if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
 		Actual_Block_Device = Decrypted_Block_Device;
-		if (TWFunc::Path_Exists(Primary_Block_Device))
+		if (TWFunc::Path_Exists(Decrypted_Block_Device))
 			Is_Present = true;
 	} else if (TWFunc::Path_Exists(Primary_Block_Device)) {
 		Is_Present = true;
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index de727f4..59451e3 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -38,6 +38,11 @@
 #include "twrpDigest.hpp"
 #include "twrpDU.hpp"
 
+#ifdef TW_HAS_MTP
+#include "mtp/mtp_MtpServer.hpp"
+#include "mtp/twrpMtp.hpp"
+#endif
+
 extern "C" {
 	#include "cutils/properties.h"
 }
@@ -51,6 +56,8 @@
 #endif
 
 TWPartitionManager::TWPartitionManager(void) {
+	mtpid = 100;
+	mtp_was_enabled = false;
 }
 
 int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
@@ -71,8 +78,7 @@
 
 		if (fstab_line[strlen(fstab_line) - 1] != '\n')
 			fstab_line[strlen(fstab_line)] = '\n';
-
-		TWPartition* partition = new TWPartition();
+		TWPartition* partition = new TWPartition(&mtpid);
 		string line = fstab_line;
 		memset(fstab_line, 0, sizeof(fstab_line));
 
@@ -1297,15 +1303,25 @@
 			return false;
 
 		gui_print("Wiping internal storage -- /data/media...\n");
+		mtp_was_enabled = TWFunc::Toggle_MTP(false);
 		TWFunc::removeDir("/data/media", false);
-		if (mkdir("/data/media", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0)
-			return -1;
+		if (mkdir("/data/media", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0) {
+			if (mtp_was_enabled) {
+				if (!Enable_MTP())
+					Disable_MTP();
+			}
+			return false;
+		}
 		if (dat->Has_Data_Media) {
 			dat->Recreate_Media_Folder();
 			// Unmount and remount - slightly hackish way to ensure that the "/sdcard" folder is still mounted properly after wiping
 			dat->UnMount(false);
 			dat->Mount(false);
 		}
+		if (mtp_was_enabled) {
+			if (!Enable_MTP())
+				Disable_MTP();
+		}
 		return true;
 	} else {
 		LOGERR("Unable to locate /data.\n");
@@ -1735,20 +1751,22 @@
 		if (TWFunc::Path_Exists(lun_file))
 			has_multiple_lun = true;
 	}
+	mtp_was_enabled = TWFunc::Toggle_MTP(false);
 	if (!has_multiple_lun) {
 		LOGINFO("Device doesn't have multiple lun files, mount current storage\n");
 		sprintf(lun_file, CUSTOM_LUN_FILE, 0);
 		if (TWFunc::Get_Root_Path(DataManager::GetCurrentStoragePath()) == "/data") {
 			TWPartition* Mount = Find_Next_Storage("", "/data");
 			if (Mount) {
-				if (!Open_Lun_File(Mount->Mount_Point, lun_file))
-					return false;
+				if (!Open_Lun_File(Mount->Mount_Point, lun_file)) {
+					goto error_handle;
+				}
 			} else {
 				LOGERR("Unable to find storage partition to mount to USB\n");
-				return false;
+				goto error_handle;
 			}
 		} else if (!Open_Lun_File(DataManager::GetCurrentStoragePath(), lun_file)) {
-			return false;
+			goto error_handle;
 		}
 	} else {
 		LOGINFO("Device has multiple lun files\n");
@@ -1757,8 +1775,9 @@
 		sprintf(lun_file, CUSTOM_LUN_FILE, 0);
 		Mount1 = Find_Next_Storage("", "/data");
 		if (Mount1) {
-			if (!Open_Lun_File(Mount1->Mount_Point, lun_file))
-				return false;
+			if (!Open_Lun_File(Mount1->Mount_Point, lun_file)) {
+				goto error_handle;
+			}
 			sprintf(lun_file, CUSTOM_LUN_FILE, 1);
 			Mount2 = Find_Next_Storage(Mount1->Mount_Point, "/data");
 			if (Mount2) {
@@ -1766,11 +1785,16 @@
 			}
 		} else {
 			LOGERR("Unable to find storage partition to mount to USB\n");
-			return false;
+			goto error_handle;
 		}
 	}
 	property_set("sys.storage.ums_enabled", "1");
 	return true;
+error_handle:
+	if (mtp_was_enabled)
+		if (!Enable_MTP())
+			Disable_MTP();
+	return false;
 }
 
 int TWPartitionManager::usb_storage_disable(void) {
@@ -1789,6 +1813,9 @@
 	Update_System_Details();
 	UnMount_Main_Partitions();
 	property_set("sys.storage.ums_enabled", "0");
+	if (mtp_was_enabled)
+		if (!Enable_MTP())
+			Disable_MTP();
 	if (ret < 0 && index == 0) {
 		LOGERR("Unable to write to ums lunfile '%s'.", lun_file);
 		return false;
@@ -2123,3 +2150,69 @@
 	}
 	return res;
 }
+
+bool TWPartitionManager::Enable_MTP(void) {
+#ifdef TW_HAS_MTP
+	if (mtpthread) {
+		LOGERR("MTP already enabled\n");
+		return true;
+	}
+	//Launch MTP Responder
+	LOGINFO("Starting MTP\n");
+	char vendor[PROPERTY_VALUE_MAX];
+	char product[PROPERTY_VALUE_MAX];
+	int count = 0;
+	property_set("sys.usb.config", "none");
+	property_get("usb.vendor", vendor, "18D1");
+	property_get("usb.product.mtpadb", product, "4EE2");
+	string vendorstr = vendor;
+	string productstr = product;
+	TWFunc::write_file("/sys/class/android_usb/android0/idVendor", vendorstr);
+	TWFunc::write_file("/sys/class/android_usb/android0/idProduct", productstr);
+	property_set("sys.usb.config", "mtp,adb");
+	std::vector<TWPartition*>::iterator iter;
+	twrpMtp *mtp = new twrpMtp();
+	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if ((*iter)->Is_Storage && (*iter)->Is_Present && (*iter)->Mount(false)) {
+			printf("twrp mtpid: %d\n", (*iter)->mtpid);
+			mtp->addStorage((*iter)->Storage_Name, (*iter)->Storage_Path, (*iter)->mtpid);
+			count++;
+		}
+	}
+	if (count) {
+		mtpthread = mtp->runserver();
+		DataManager::SetValue("tw_mtp_enabled", 1);
+		return true;
+	}
+	LOGERR("No valid storage partitions found for MTP.\n");
+#else
+	LOGERR("MTP support not included\n");
+#endif
+	DataManager::SetValue("tw_mtp_enabled", 0);
+	return false;
+}
+
+bool TWPartitionManager::Disable_MTP(void) {
+#ifdef TW_HAS_MTP
+	char vendor[PROPERTY_VALUE_MAX];
+	char product[PROPERTY_VALUE_MAX];
+	property_set("sys.usb.config", "none");
+	property_get("usb.vendor", vendor, "18D1");
+	property_get("usb.product.adb", product, "D002");
+	string vendorstr = vendor;
+	string productstr = product;
+	TWFunc::write_file("/sys/class/android_usb/android0/idVendor", vendorstr);
+	TWFunc::write_file("/sys/class/android_usb/android0/idProduct", productstr);
+	if (mtpthread) {
+		pthread_kill(mtpthread, 0);
+		mtpthread = NULL;
+	}
+	property_set("sys.usb.config", "adb");
+	DataManager::SetValue("tw_mtp_enabled", 0);
+	return true;
+#else
+	LOGERR("MTP support not included\n");
+	DataManager::SetValue("tw_mtp_enabled", 0);
+	return false;
+#endif
+}
diff --git a/partitions.hpp b/partitions.hpp
index 0d74315..00f435a 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -45,7 +45,7 @@
 	};
 
 public:
-	TWPartition();
+	TWPartition(int *id);
 	virtual ~TWPartition();
 
 public:
@@ -72,6 +72,7 @@
 	string Current_File_System;                                               // Current file system
 	string Actual_Block_Device;                                               // Actual block device (one of primary, alternate, or decrypted)
 	string MTD_Name;                                                          // Name of the partition for MTD devices
+	bool Is_Present;                                                          // Indicates if the partition is currently present as a block device
 
 private:
 	bool Process_Fstab_Line(string Line, bool Display_Error);                 // Processes a fstab line
@@ -127,8 +128,9 @@
 	string Alternate_Block_Device;                                            // Alternate block device (e.g. /dev/block/mmcblk1)
 	string Decrypted_Block_Device;                                            // Decrypted block device available after decryption
 	bool Removable;                                                           // Indicates if this partition is removable -- affects how often we check overall size, if present, etc.
-	bool Is_Present;                                                          // Indicates if the partition is currently present as a block device
 	int Length;                                                               // Used by make_ext4fs to leave free space at the end of the partition block for things like a crypto footer
+	int *initmtpid;															  // Initial MTP ID
+	int mtpid;															      // Store MTP ID
 	unsigned long long Size;                                                  // Overall size of the partition
 	unsigned long long Used;                                                  // Overall used space
 	unsigned long long Free;                                                  // Overall free space
@@ -224,6 +226,8 @@
 	void Get_Partition_List(string ListType, std::vector<PartitionList> *Partition_List);
 	int Fstab_Processed();                                                    // Indicates if the fstab has been processed or not
 	void Output_Storage_Fstab();                                              // Creates a /cache/recovery/storage.fstab file with a list of all potential storage locations for app use
+	bool Enable_MTP();                                                        // Enables MTP
+	bool Disable_MTP();                                                       // Disables MTP
 
 private:
 	void Setup_Settings_Storage_Partition(TWPartition* Part);                 // Sets up settings storage
@@ -234,6 +238,9 @@
 	void Output_Partition(TWPartition* Part);
 	TWPartition* Find_Next_Storage(string Path, string Exclude);
 	int Open_Lun_File(string Partition_Path, string Lun_File);
+	int mtpid;
+	pthread_t mtpthread;
+	bool mtp_was_enabled;
 
 private:
 	std::vector<TWPartition*> Partitions;                                     // Vector list of all partitions
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 8a29e14..9431c94 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -26,8 +26,13 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/mke2fs
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/tune2fs
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/linker
+#RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/twrpmtp
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libc.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcutils.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcorkscrew.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libusbhost.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgccdemangle.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutils.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libdl.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_blkid.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_com_err.so
@@ -53,6 +58,11 @@
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/toolbox
 ifneq ($(TW_OEM_BUILD),true)
     RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/twrp
+else
+    TW_EXCLUDE_MTP := true
+endif
+ifneq ($(TW_EXCLUDE_MTP), true)
+    RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtwrpmtp.so
 endif
 ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
     RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext4_utils.so
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 885d352..1798c49 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -1260,4 +1260,22 @@
 	return -1;
 }
 
+bool TWFunc::Toggle_MTP(bool enable) {
+#ifdef TW_HAS_MTP
+	static int was_enabled = false;
+
+	if (enable && was_enabled) {
+		if (!PartitionManager.Enable_MTP())
+			PartitionManager.Disable_MTP();
+	} else {
+		was_enabled = DataManager::GetIntValue("tw_mtp_enabled");
+		PartitionManager.Disable_MTP();
+		usleep(500);
+	}
+	return was_enabled;
+#else
+	return false;
+#endif
+}
+
 #endif // ndef BUILD_TWRPTAR_MAIN
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 5f46d4f..c46738e 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -85,6 +85,7 @@
 	static std::vector<std::string> Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty = true); // Splits string by delimiter
 	static bool Create_Dir_Recursive(const std::string& path, mode_t mode = 0755, uid_t uid = -1, gid_t gid = -1);  // Create directory and it's parents, if they don't exist. mode, uid and gid are set to all _newly_ created folders. If whole path exists, do nothing.
 	static int Set_Brightness(std::string brightness_value); // Well, you can read, it does what it says, passing return int from TWFunc::Write_File ;)
+	static bool Toggle_MTP(bool enable);                                        // Disables MTP if enable is false and re-enables MTP if enable is true and it was enabled the last time it was toggled off
 
 private:
 	static void Copy_Log(string Source, string Destination);
diff --git a/twrp.cpp b/twrp.cpp
index 8b60ee1..5f58e41 100644
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -82,6 +82,8 @@
 	crash_counter = atoi(crash_prop_val) + 1;
 	snprintf(crash_prop_val, sizeof(crash_prop_val), "%d", crash_counter);
 	property_set("twrp.crash_counter", crash_prop_val);
+	property_set("ro.twrp.boot", "1");
+	property_set("ro.twrp.version", TW_VERSION_STR);
 
 	time_t StartupTime = time(NULL);
 	printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&StartupTime));
@@ -279,6 +281,23 @@
 		OpenRecoveryScript::Run_OpenRecoveryScript();
 	}
 
+	// Enable MTP?
+	if (DataManager::GetIntValue(TW_IS_ENCRYPTED) != 0) {
+		if (DataManager::GetIntValue(TW_IS_DECRYPTED) != 0 && DataManager::GetIntValue("tw_mtp_enabled") == 1) {
+			LOGINFO("Enabling MTP during startup\n");
+			if (!PartitionManager.Enable_MTP())
+				PartitionManager.Disable_MTP();
+			else
+				gui_print("MTP Enabled\n");
+		}
+	} else if (DataManager::GetIntValue("tw_mtp_enabled") == 1) {
+		LOGINFO("Enabling MTP during startup\n");
+		if (!PartitionManager.Enable_MTP())
+			PartitionManager.Disable_MTP();
+		else
+			gui_print("MTP Enabled\n");
+	}
+
 	// Launch the main GUI
 	gui_start();
 
diff --git a/variables.h b/variables.h
index 4e5de44..1c1957f 100644
--- a/variables.h
+++ b/variables.h
@@ -17,7 +17,7 @@
 #ifndef _VARIABLES_HEADER_
 #define _VARIABLES_HEADER_
 
-#define TW_VERSION_STR              "2.7.1.0"
+#define TW_VERSION_STR              "2.8.0.0"
 
 #define TW_USE_COMPRESSION_VAR      "tw_use_compression"
 #define TW_FILENAME                 "tw_filename"