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

Change-Id: I6c9c522b9c9de5dc139e2ecb0141008182ba07f0
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);
+	}
+}