This update splits old MTP code and new MTP code from Google into two trees, legacy and ffs. Depending on the SDK level, the build system will select the correct version. The reason for separating the versions out are due to older android trees not supporting the updated MTP code from Google. Most MTP code is from Google, with additions needed from implementing the Java functions in C++ for TWRP and FFS. We assume if you are in android-9.0 or above, your kernel has support for FFS over MTP. Verify that your init.rc is mounting the MTP FFS driver to the proper location. Change-Id: I4b107b239bd9bc5699527f9c8c77d9079f264a7e
851 lines
28 KiB
C++
Executable File
851 lines
28 KiB
C++
Executable File
/*
|
|
* 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 <assert.h>
|
|
#include <cutils/properties.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <libgen.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "MtpDataPacket.h"
|
|
#include "MtpDatabase.h"
|
|
#include "MtpDebug.h"
|
|
#include "MtpObjectInfo.h"
|
|
#include "MtpProperty.h"
|
|
#include "MtpStorage.h"
|
|
#include "MtpStringBuffer.h"
|
|
#include "MtpUtils.h"
|
|
#include "mtp.h"
|
|
#include "mtp_MtpDatabase.hpp"
|
|
|
|
IMtpDatabase::IMtpDatabase() {
|
|
storagenum = 0;
|
|
count = -1;
|
|
}
|
|
|
|
IMtpDatabase::~IMtpDatabase() {
|
|
std::map<int, MtpStorage*>::iterator i;
|
|
for (i = storagemap.begin(); i != storagemap.end(); i++) {
|
|
delete i->second;
|
|
}
|
|
}
|
|
|
|
int IMtpDatabase::DEVICE_PROPERTIES[3] = { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,
|
|
MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,
|
|
MTP_DEVICE_PROPERTY_IMAGE_SIZE };
|
|
|
|
int IMtpDatabase::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,
|
|
// TODO: why is DISPLAY_NAME not here?
|
|
MTP_PROPERTY_DATE_ADDED
|
|
};
|
|
|
|
int IMtpDatabase::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 IMtpDatabase::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 IMtpDatabase::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 IMtpDatabase::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 IMtpDatabase::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 IMtpDatabase::beginSendObject(const char* path, MtpObjectFormat format,
|
|
MtpObjectHandle parent, MtpStorageID storageID,
|
|
uint64_t size, time_t modified) {
|
|
if (storagemap.find(storageID) == storagemap.end()) return kInvalidObjectHandle;
|
|
return storagemap[storageID]->beginSendObject(path, format, parent, size, modified);
|
|
}
|
|
|
|
void IMtpDatabase::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);
|
|
}
|
|
std::map<int, MtpStorage*>::iterator storit;
|
|
for (storit = storagemap.begin(); storit != storagemap.end(); storit++)
|
|
storit->second->endSendObject(path, handle, format, succeeded);
|
|
}
|
|
|
|
void IMtpDatabase::createDB(MtpStorage* storage, MtpStorageID storageID) {
|
|
storagemap[storageID] = storage;
|
|
storage->createDB();
|
|
}
|
|
|
|
void IMtpDatabase::destroyDB(MtpStorageID storageID) {
|
|
MtpStorage* storage = storagemap[storageID];
|
|
storagemap.erase(storageID);
|
|
delete storage;
|
|
}
|
|
|
|
MtpObjectHandleList* IMtpDatabase::getObjectList(MtpStorageID storageID,
|
|
__attribute__((unused)) MtpObjectFormat format,
|
|
MtpObjectHandle parent) {
|
|
MTPD("IMtpDatabase::getObjectList::storageID: %d\n", storageID);
|
|
MtpObjectHandleList* list = storagemap[storageID]->getObjectList(storageID, parent);
|
|
MTPD("IMtpDatabase::getObjectList::list size: %d\n", list->size());
|
|
return list;
|
|
}
|
|
|
|
int IMtpDatabase::getNumObjects(MtpStorageID storageID,
|
|
__attribute__((unused)) MtpObjectFormat format,
|
|
MtpObjectHandle parent) {
|
|
MtpObjectHandleList* list = storagemap[storageID]->getObjectList(storageID, parent);
|
|
int size = list->size();
|
|
delete list;
|
|
return size;
|
|
}
|
|
|
|
MtpObjectFormatList* IMtpDatabase::getSupportedPlaybackFormats() {
|
|
// This function tells the host PC which file formats the device supports
|
|
MtpObjectFormatList* list = new MtpObjectFormatList();
|
|
int length = sizeof(SUPPORTED_PLAYBACK_FORMATS) / sizeof(SUPPORTED_PLAYBACK_FORMATS[0]);
|
|
MTPD("IMtpDatabase::getSupportedPlaybackFormats length: %i\n", length);
|
|
for (int i = 0; i < length; i++) {
|
|
MTPD("supported playback format: %x\n", SUPPORTED_PLAYBACK_FORMATS[i]);
|
|
list->push_back(SUPPORTED_PLAYBACK_FORMATS[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
MtpObjectFormatList* IMtpDatabase::getSupportedCaptureFormats() {
|
|
// Android OS implementation of this function returns NULL
|
|
// so we are not implementing this function either.
|
|
MTPD(
|
|
"IMtpDatabase::getSupportedCaptureFormats returning NULL (This is what Android does as "
|
|
"well).\n");
|
|
return NULL;
|
|
}
|
|
|
|
MtpObjectPropertyList* IMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
|
|
int* properties;
|
|
MtpObjectPropertyList* list = new MtpObjectPropertyList();
|
|
int length = 0;
|
|
switch (format) {
|
|
case MTP_FORMAT_MP3:
|
|
case MTP_FORMAT_WAV:
|
|
case MTP_FORMAT_WMA:
|
|
case MTP_FORMAT_OGG:
|
|
case MTP_FORMAT_AAC:
|
|
properties = AUDIO_PROPERTIES;
|
|
length = sizeof(AUDIO_PROPERTIES) / sizeof(AUDIO_PROPERTIES[0]);
|
|
break;
|
|
case MTP_FORMAT_MPEG:
|
|
case MTP_FORMAT_3GP_CONTAINER:
|
|
case MTP_FORMAT_WMV:
|
|
properties = VIDEO_PROPERTIES;
|
|
length = sizeof(VIDEO_PROPERTIES) / sizeof(VIDEO_PROPERTIES[0]);
|
|
break;
|
|
case MTP_FORMAT_EXIF_JPEG:
|
|
case MTP_FORMAT_GIF:
|
|
case MTP_FORMAT_PNG:
|
|
case MTP_FORMAT_BMP:
|
|
properties = IMAGE_PROPERTIES;
|
|
length = sizeof(IMAGE_PROPERTIES) / sizeof(IMAGE_PROPERTIES[0]);
|
|
break;
|
|
case 0:
|
|
properties = ALL_PROPERTIES;
|
|
length = sizeof(ALL_PROPERTIES) / sizeof(ALL_PROPERTIES[0]);
|
|
break;
|
|
default:
|
|
properties = FILE_PROPERTIES;
|
|
length = sizeof(FILE_PROPERTIES) / sizeof(FILE_PROPERTIES[0]);
|
|
}
|
|
MTPD("IMtpDatabase::getSupportedObjectProperties length is: %i, format: %x", length, format);
|
|
for (int i = 0; i < length; i++) {
|
|
MTPD("supported object property: %x\n", properties[i]);
|
|
list->push_back(properties[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
MtpDevicePropertyList* IMtpDatabase::getSupportedDeviceProperties() {
|
|
MtpDevicePropertyList* list = new MtpDevicePropertyList();
|
|
int length = sizeof(DEVICE_PROPERTIES) / sizeof(DEVICE_PROPERTIES[0]);
|
|
MTPD("IMtpDatabase::getSupportedDeviceProperties length was: %i\n", length);
|
|
for (int i = 0; i < length; i++) list->push_back(DEVICE_PROPERTIES[i]);
|
|
return list;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
|
|
MtpObjectProperty property,
|
|
MtpDataPacket& packet) {
|
|
MTPD("IMtpDatabase::getObjectPropertyValue mtpid: %u, property: %x\n", handle, property);
|
|
int type;
|
|
MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
MtpStorage::PropEntry prop;
|
|
if (!getObjectPropertyInfo(property, type)) {
|
|
MTPE("IMtpDatabase::getObjectPropertyValue 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, prop) == 0) {
|
|
result = MTP_RESPONSE_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (result != MTP_RESPONSE_OK) {
|
|
MTPE("IMtpDatabase::getObjectPropertyValue unable to locate handle: %u\n", handle);
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
uint64_t longValue = prop.intvalue;
|
|
// 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;
|
|
}
|
|
|
|
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.putUInt128(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();
|
|
}*/
|
|
packet.putString(prop.strvalue.c_str());
|
|
MTPD("MTP_TYPE_STR: %x = %s\n", prop.property, prop.strvalue.c_str());
|
|
// 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 IMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
|
|
MtpObjectProperty property,
|
|
MtpDataPacket& packet) {
|
|
int type;
|
|
MTPD("IMtpDatabase::setObjectPropertyValue start\n");
|
|
if (!getObjectPropertyInfo(property, type)) {
|
|
MTPE("IMtpDatabase::setObjectPropertyValue returning MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED\n");
|
|
return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
|
|
}
|
|
MTPD("IMtpDatabase::setObjectPropertyValue continuing\n");
|
|
|
|
int8_t int8_t_value;
|
|
uint8_t uint8_t_value;
|
|
int16_t int16_t_value;
|
|
uint16_t uint16_t_value;
|
|
int32_t int32_t_value;
|
|
uint32_t uint32_t_value;
|
|
int64_t int64_t_value;
|
|
uint64_t uint64_t_value;
|
|
std::string stringValue;
|
|
|
|
switch (type) {
|
|
case MTP_TYPE_INT8:
|
|
MTPD("int8\n");
|
|
packet.getInt8(int8_t_value);
|
|
break;
|
|
case MTP_TYPE_UINT8:
|
|
MTPD("uint8\n");
|
|
packet.getUInt8(uint8_t_value);
|
|
break;
|
|
case MTP_TYPE_INT16:
|
|
MTPD("int16\n");
|
|
packet.getInt16(int16_t_value);
|
|
break;
|
|
case MTP_TYPE_UINT16:
|
|
MTPD("uint16\n");
|
|
packet.getUInt16(uint16_t_value);
|
|
break;
|
|
case MTP_TYPE_INT32:
|
|
MTPD("int32\n");
|
|
packet.getInt32(int32_t_value);
|
|
break;
|
|
case MTP_TYPE_UINT32:
|
|
MTPD("uint32\n");
|
|
packet.getUInt32(uint32_t_value);
|
|
break;
|
|
case MTP_TYPE_INT64:
|
|
MTPD("int64\n");
|
|
packet.getInt64(int64_t_value);
|
|
break;
|
|
case MTP_TYPE_UINT64:
|
|
MTPD("uint64\n");
|
|
packet.getUInt64(uint64_t_value);
|
|
break;
|
|
case MTP_TYPE_STR: {
|
|
MTPD("string\n");
|
|
MtpStringBuffer buffer;
|
|
packet.getString(buffer);
|
|
stringValue = buffer;
|
|
break;
|
|
}
|
|
default:
|
|
MTPE("IMtpDatabase::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("IMtpDatabase::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("IMtpDatabase::setObjectPropertyValue property %x not supported.\n", property);
|
|
result = MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
|
|
}
|
|
MTPD("IMtpDatabase::setObjectPropertyValue returning %d\n", result);
|
|
return result;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::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("IMtpDatabase::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("IMtpDatabase::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("IMtpDatabase::getDevicePropertyValue unsupported type %i in getDevicePropertyValue\n",
|
|
type);
|
|
return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
|
|
}
|
|
|
|
return MTP_RESPONSE_OK;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::setDevicePropertyValue(__attribute__((unused))
|
|
MtpDeviceProperty property,
|
|
__attribute__((unused))
|
|
MtpDataPacket& packet) {
|
|
MTPE("IMtpDatabase::setDevicePropertyValue not implemented, returning 0\n");
|
|
return 0;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::resetDeviceProperty(__attribute__((unused))
|
|
MtpDeviceProperty property) {
|
|
MTPE("IMtpDatabase::resetDeviceProperty not implemented, returning -1\n");
|
|
return -1;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::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("IMtpDatabase::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("IMtpDatabase::getObjectPropertyList MTP_RESPOSNE_INVALID_OBJECT_HANDLE %i\n", handle);
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::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("IMtpDatabase::getObjectInfo MTP_RESPONSE_INVALID_OBJECT_HANDLE %i\n", handle);
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
void* IMtpDatabase::getThumbnail(__attribute__((unused)) MtpObjectHandle handle,
|
|
__attribute__((unused)) size_t& outThumbSize) {
|
|
MTPE("IMtpDatabase::getThumbnail not implemented, returning 0\n");
|
|
return 0;
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
|
|
MtpStringBuffer& outFilePath,
|
|
int64_t& outFileLength,
|
|
MtpObjectFormat& outFormat) {
|
|
std::map<int, MtpStorage*>::iterator storit;
|
|
for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
|
|
MTPD("IMtpDatabase::getObjectFilePath calling getObjectFilePath\n");
|
|
if (storit->second->getObjectFilePath(handle, outFilePath, outFileLength, outFormat) == 0) {
|
|
MTPD("MTP_RESPONSE_OK\n");
|
|
return MTP_RESPONSE_OK;
|
|
}
|
|
}
|
|
MTPE("IMtpDatabase::getObjectFilePath MTP_RESPOSNE_INVALID_OBJECT_HANDLE %i\n", handle);
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
// MtpResponseCode IMtpDatabase::deleteFile(MtpObjectHandle handle) {
|
|
// MTPD("IMtpDatabase::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("IMtpDatabase::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 IMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
|
|
int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
|
|
const PropertyTableEntry* entry = kObjectPropertyTable;
|
|
MTPD("IMtpDatabase::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 IMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
|
|
int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
|
|
const PropertyTableEntry* entry = kDevicePropertyTable;
|
|
MTPD("IMtpDatabase::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* IMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
|
|
// call function and place files with associated handles into int array
|
|
MTPD(
|
|
"IMtpDatabase::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 IMtpDatabase::setObjectReferences(__attribute__((unused)) MtpObjectHandle handle,
|
|
__attribute__((unused))
|
|
MtpObjectHandleList* references) {
|
|
MTPE("IMtpDatabase::setObjectReferences not implemented, returning 0\n");
|
|
return 0;
|
|
}
|
|
|
|
MtpProperty* IMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
|
|
MtpObjectFormat format) {
|
|
MTPD("IMtpDatabase::getObjectPropertyDesc start\n");
|
|
MtpProperty* result = NULL;
|
|
switch (property) {
|
|
case MTP_PROPERTY_OBJECT_FORMAT:
|
|
// use format as default value
|
|
result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
|
|
break;
|
|
case MTP_PROPERTY_PROTECTION_STATUS:
|
|
case MTP_PROPERTY_TRACK:
|
|
result = new MtpProperty(property, MTP_TYPE_UINT16);
|
|
break;
|
|
case MTP_PROPERTY_STORAGE_ID:
|
|
case MTP_PROPERTY_PARENT_OBJECT:
|
|
case MTP_PROPERTY_DURATION:
|
|
result = new MtpProperty(property, MTP_TYPE_UINT32);
|
|
break;
|
|
case MTP_PROPERTY_OBJECT_SIZE:
|
|
result = new MtpProperty(property, MTP_TYPE_UINT64);
|
|
break;
|
|
case MTP_PROPERTY_PERSISTENT_UID:
|
|
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:
|
|
result = new MtpProperty(property, MTP_TYPE_STR);
|
|
break;
|
|
case MTP_PROPERTY_DATE_MODIFIED:
|
|
case MTP_PROPERTY_DATE_ADDED:
|
|
case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
|
|
result = new MtpProperty(property, MTP_TYPE_STR);
|
|
result->setFormDateTime();
|
|
break;
|
|
case MTP_PROPERTY_OBJECT_FILE_NAME:
|
|
// We allow renaming files and folders
|
|
result = new MtpProperty(property, MTP_TYPE_STR, true);
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MtpProperty* IMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
|
|
MtpProperty* result = NULL;
|
|
bool writable = false;
|
|
switch (property) {
|
|
case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
|
|
case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
|
|
writable = true;
|
|
// fall through
|
|
case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
|
|
result = new MtpProperty(property, MTP_TYPE_STR, writable);
|
|
|
|
// get current value
|
|
// TODO: add actual values
|
|
result->setCurrentValue(0);
|
|
result->setDefaultValue(0);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void IMtpDatabase::sessionStarted() {
|
|
MTPD("IMtpDatabase::sessionStarted not implemented or does nothing, returning\n");
|
|
return;
|
|
}
|
|
|
|
void IMtpDatabase::sessionEnded() {
|
|
MTPD("IMtpDatabase::sessionEnded not implemented or does nothing, returning\n");
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void IMtpDatabase::lockMutex(void) {
|
|
std::map<int, MtpStorage*>::iterator storit;
|
|
for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
|
|
storit->second->lockMutex(0);
|
|
}
|
|
}
|
|
|
|
void IMtpDatabase::unlockMutex(void) {
|
|
std::map<int, MtpStorage*>::iterator storit;
|
|
for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
|
|
storit->second->unlockMutex(0);
|
|
}
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
|
|
MTPD("IMtoDatabase::beginDeleteObject handle: %u\n", handle);
|
|
std::map<int, MtpStorage*>::iterator storit;
|
|
for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
|
|
if (storit->second->deleteFile(handle) == 0) {
|
|
MTPD("IMtpDatabase::beginDeleteObject::MTP_RESPONSE_OK\n");
|
|
return MTP_RESPONSE_OK;
|
|
}
|
|
}
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
void IMtpDatabase::endDeleteObject(MtpObjectHandle handle __unused, bool succeeded __unused) {
|
|
MTPD("IMtpDatabase::endDeleteObject not implemented yet\n");
|
|
}
|
|
|
|
void IMtpDatabase::rescanFile(const char* path __unused, MtpObjectHandle handle __unused,
|
|
MtpObjectFormat format __unused) {
|
|
MTPD("IMtpDatabase::rescanFile not implemented yet\n");
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::beginMoveObject(MtpObjectHandle handle __unused,
|
|
MtpObjectHandle newParent __unused,
|
|
MtpStorageID newStorage __unused) {
|
|
MTPD("IMtpDatabase::beginMoveObject not implemented yet\n");
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
void IMtpDatabase::endMoveObject(MtpObjectHandle oldParent __unused,
|
|
MtpObjectHandle newParent __unused,
|
|
MtpStorageID oldStorage __unused, MtpStorageID newStorage __unused,
|
|
MtpObjectHandle handle __unused, bool succeeded __unused) {
|
|
MTPD("IMtpDatabase::endMoveObject not implemented yet\n");
|
|
}
|
|
|
|
MtpResponseCode IMtpDatabase::beginCopyObject(MtpObjectHandle handle __unused,
|
|
MtpObjectHandle newParent __unused,
|
|
MtpStorageID newStorage __unused) {
|
|
MTPD("IMtpDatabase::beginCopyObject not implemented yet\n");
|
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
|
}
|
|
|
|
void IMtpDatabase::endCopyObject(MtpObjectHandle handle __unused, bool succeeded __unused) {
|
|
MTPD("IMtpDatabase::endCopyObject not implemented yet\n");
|
|
}
|