Checkpoint work on MTP and PTP investigation.
This change includes work in progress on a C++ library for both host and device MTP and PTP support. Currently the makefile builds two test programs: mtptest - a command line test program that implements a small subset of device side MTP. Requires a kernel driver that has not been checked in yet. ptptest - a host tool to test USB host support for detecting and communicating with digital cameras over PTP. Runs on Linux host. Later this will be reformulated as a native library that will be used in the media process. Change-Id: I81aab279975b600b59d99013ab97f9adf0b58da7 Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
69
media/mtp/Android.mk
Normal file
69
media/mtp/Android.mk
Normal file
@@ -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.
|
||||
#
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
mtptest.cpp \
|
||||
MtpDatabase.cpp \
|
||||
MtpDataPacket.cpp \
|
||||
MtpDebug.cpp \
|
||||
MtpPacket.cpp \
|
||||
MtpRequestPacket.cpp \
|
||||
MtpResponsePacket.cpp \
|
||||
MtpServer.cpp \
|
||||
MtpStringBuffer.cpp \
|
||||
MtpStorage.cpp \
|
||||
MtpUtils.cpp \
|
||||
SqliteDatabase.cpp \
|
||||
SqliteStatement.cpp \
|
||||
|
||||
LOCAL_MODULE:= mtptest
|
||||
|
||||
LOCAL_C_INCLUDES := external/sqlite/dist
|
||||
|
||||
LOCAL_CFLAGS := -DMTP_DEVICE
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libutils libsqlite
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := ptptest
|
||||
LOCAL_SRC_FILES:= \
|
||||
ptptest.cpp \
|
||||
MtpClient.cpp \
|
||||
MtpDataPacket.cpp \
|
||||
MtpDebug.cpp \
|
||||
MtpPacket.cpp \
|
||||
MtpRequestPacket.cpp \
|
||||
MtpResponsePacket.cpp \
|
||||
MtpStringBuffer.cpp \
|
||||
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libusbhost
|
||||
LOCAL_LDLIBS := -lpthread
|
||||
|
||||
LOCAL_CFLAGS := -g -DMTP_HOST
|
||||
LOCAL_LDFLAGS := -g
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
|
||||
endif
|
||||
136
media/mtp/MtpClient.cpp
Normal file
136
media/mtp/MtpClient.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <usbhost/usbhost.h>
|
||||
|
||||
#include "MtpClient.h"
|
||||
#include "MtpDebug.h"
|
||||
#include "MtpStringBuffer.h"
|
||||
|
||||
MtpClient::MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
|
||||
struct usb_endpoint *ep_intr)
|
||||
: mEndpointIn(ep_in),
|
||||
mEndpointOut(ep_out),
|
||||
mEndpointIntr(ep_intr),
|
||||
mSessionID(0),
|
||||
mTransactionID(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MtpClient::~MtpClient() {
|
||||
}
|
||||
|
||||
|
||||
bool MtpClient::openSession() {
|
||||
printf("openSession\n");
|
||||
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 MtpClient::getDeviceInfo() {
|
||||
mRequest.reset();
|
||||
if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
|
||||
return false;
|
||||
if (!readData())
|
||||
return false;
|
||||
MtpResponseCode ret = readResponse();
|
||||
if (ret == MTP_RESPONSE_OK) {
|
||||
MtpStringBuffer string;
|
||||
|
||||
// fill in device info
|
||||
printf("MTP standard version: %d\n", mData.getUInt16());
|
||||
printf("MTP Vendor Extension ID: %d\n", mData.getUInt32());
|
||||
printf("MTP vendor extension version: %d\n", mData.getUInt16());
|
||||
mData.getString(string);
|
||||
printf("vendor extension desc %s\n", (const char *)string);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MtpClient::closeSession() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MtpClient::sendRequest(MtpOperationCode operation) {
|
||||
printf("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
|
||||
mRequest.setOperationCode(operation);
|
||||
if (mTransactionID > 0)
|
||||
mRequest.setTransactionID(mTransactionID++);
|
||||
int ret = mRequest.write(mEndpointOut);
|
||||
mRequest.dump();
|
||||
return (ret > 0);
|
||||
}
|
||||
|
||||
bool MtpClient::sendData(MtpOperationCode operation) {
|
||||
printf("sendData\n");
|
||||
mData.setOperationCode(mRequest.getOperationCode());
|
||||
mData.setTransactionID(mRequest.getTransactionID());
|
||||
int ret = mData.write(mEndpointOut);
|
||||
mData.dump();
|
||||
return (ret > 0);
|
||||
}
|
||||
|
||||
bool MtpClient::readData() {
|
||||
int ret = mData.read(mEndpointIn);
|
||||
printf("readData returned %d\n", ret);
|
||||
if (ret >= MTP_CONTAINER_HEADER_SIZE) {
|
||||
mData.dump();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
printf("readResponse failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MtpResponseCode MtpClient::readResponse() {
|
||||
printf("readResponse\n");
|
||||
int ret = mResponse.read(mEndpointIn);
|
||||
if (ret >= MTP_CONTAINER_HEADER_SIZE) {
|
||||
mResponse.dump();
|
||||
return mResponse.getResponseCode();
|
||||
}
|
||||
else {
|
||||
printf("readResponse failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
59
media/mtp/MtpClient.h
Normal file
59
media/mtp/MtpClient.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_CLIENT_H
|
||||
#define _MTP_CLIENT_H
|
||||
|
||||
#include "MtpRequestPacket.h"
|
||||
#include "MtpDataPacket.h"
|
||||
#include "MtpResponsePacket.h"
|
||||
#include "mtp.h"
|
||||
|
||||
#include "MtpUtils.h"
|
||||
|
||||
class MtpClient {
|
||||
private:
|
||||
struct usb_endpoint *mEndpointIn;
|
||||
struct usb_endpoint *mEndpointOut;
|
||||
struct usb_endpoint *mEndpointIntr;
|
||||
|
||||
// current session ID
|
||||
MtpSessionID mSessionID;
|
||||
// current transaction ID
|
||||
MtpTransactionID mTransactionID;
|
||||
|
||||
MtpRequestPacket mRequest;
|
||||
MtpDataPacket mData;
|
||||
MtpResponsePacket mResponse;
|
||||
|
||||
public:
|
||||
MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
|
||||
struct usb_endpoint *ep_intr);
|
||||
virtual ~MtpClient();
|
||||
|
||||
bool openSession();
|
||||
bool getDeviceInfo();
|
||||
bool closeSession();
|
||||
|
||||
private:
|
||||
bool sendRequest(MtpOperationCode operation);
|
||||
bool sendData(MtpOperationCode operation);
|
||||
bool readData();
|
||||
MtpResponseCode readResponse();
|
||||
|
||||
};
|
||||
|
||||
#endif // _MTP_CLIENT_H
|
||||
296
media/mtp/MtpDataPacket.cpp
Normal file
296
media/mtp/MtpDataPacket.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "MtpDataPacket.h"
|
||||
#include "MtpStringBuffer.h"
|
||||
|
||||
MtpDataPacket::MtpDataPacket()
|
||||
: MtpPacket(512),
|
||||
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::getString(MtpStringBuffer& string)
|
||||
{
|
||||
string.readFromPacket(this);
|
||||
}
|
||||
|
||||
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::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::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);
|
||||
}
|
||||
|
||||
#ifdef MTP_DEVICE
|
||||
int MtpDataPacket::read(int fd) {
|
||||
// first read the header
|
||||
int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||
printf("MtpDataPacket::read 1 returned %d\n", ret);
|
||||
if (ret != MTP_CONTAINER_HEADER_SIZE)
|
||||
return -1;
|
||||
// then the following data
|
||||
int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
|
||||
int remaining = total - MTP_CONTAINER_HEADER_SIZE;
|
||||
printf("total: %d, remaining: %d\n", total, remaining);
|
||||
ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
|
||||
printf("MtpDataPacket::read 2 returned %d\n", ret);
|
||||
if (ret != remaining)
|
||||
return -1;
|
||||
|
||||
mPacketSize = total;
|
||||
mOffset = MTP_CONTAINER_HEADER_SIZE;
|
||||
return total;
|
||||
}
|
||||
|
||||
int MtpDataPacket::readDataHeader(int fd) {
|
||||
int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||
if (ret > 0)
|
||||
mPacketSize = ret;
|
||||
else
|
||||
mPacketSize = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int MtpDataPacket::write(int fd) {
|
||||
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
|
||||
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
|
||||
|
||||
// send header separately from data
|
||||
int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||
if (ret == MTP_CONTAINER_HEADER_SIZE)
|
||||
ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
|
||||
mPacketSize - MTP_CONTAINER_HEADER_SIZE);
|
||||
return (ret < 0 ? ret : 0);
|
||||
}
|
||||
|
||||
int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
|
||||
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
|
||||
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
|
||||
int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||
return (ret < 0 ? ret : 0);
|
||||
}
|
||||
#endif // MTP_DEVICE
|
||||
|
||||
#ifdef MTP_HOST
|
||||
int MtpDataPacket::read(struct usb_endpoint *ep) {
|
||||
// first read the header
|
||||
int ret = transfer(ep, mBuffer, mBufferSize);
|
||||
printf("MtpDataPacket::transfer returned %d\n", ret);
|
||||
if (ret >= 0)
|
||||
mPacketSize = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int MtpDataPacket::write(struct usb_endpoint *ep) {
|
||||
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
|
||||
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
|
||||
|
||||
// send header separately from data
|
||||
int ret = transfer(ep, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||
if (ret == MTP_CONTAINER_HEADER_SIZE)
|
||||
ret = transfer(ep, mBuffer + MTP_CONTAINER_HEADER_SIZE,
|
||||
mPacketSize - MTP_CONTAINER_HEADER_SIZE);
|
||||
return (ret < 0 ? ret : 0);
|
||||
}
|
||||
|
||||
#endif // MTP_HOST
|
||||
89
media/mtp/MtpDataPacket.h
Normal file
89
media/mtp/MtpDataPacket.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_DATA_PACKET_H
|
||||
#define _MTP_DATA_PACKET_H
|
||||
|
||||
#include "MtpPacket.h"
|
||||
#include "mtp.h"
|
||||
|
||||
class MtpDataPacket : public MtpPacket {
|
||||
private:
|
||||
// current offset for get/put methods
|
||||
int mOffset;
|
||||
|
||||
public:
|
||||
MtpDataPacket();
|
||||
virtual ~MtpDataPacket();
|
||||
|
||||
virtual void reset();
|
||||
|
||||
void setOperationCode(MtpOperationCode code);
|
||||
void setTransactionID(MtpTransactionID id);
|
||||
|
||||
inline 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 getString(MtpStringBuffer& string);
|
||||
|
||||
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 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 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);
|
||||
inline void putEmptyString() { putUInt16(0); }
|
||||
inline void putEmptyArray() { putUInt32(0); }
|
||||
|
||||
|
||||
#ifdef MTP_DEVICE
|
||||
// fill our buffer with data from the given file descriptor
|
||||
int read(int fd);
|
||||
int readDataHeader(int fd);
|
||||
|
||||
// write our data to the given file descriptor
|
||||
int write(int fd);
|
||||
int writeDataHeader(int fd, uint32_t length);
|
||||
#endif
|
||||
|
||||
#ifdef MTP_HOST
|
||||
int read(struct usb_endpoint *ep);
|
||||
int write(struct usb_endpoint *ep);
|
||||
#endif
|
||||
|
||||
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
|
||||
};
|
||||
|
||||
#endif // _MTP_DATA_PACKET_H
|
||||
386
media/mtp/MtpDatabase.cpp
Normal file
386
media/mtp/MtpDatabase.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MtpDatabase.h"
|
||||
#include "MtpDataPacket.h"
|
||||
#include "SqliteDatabase.h"
|
||||
#include "SqliteStatement.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#define ID_COLUMN 1
|
||||
#define PATH_COLUMN 2
|
||||
#define FORMAT_COLUMN 3
|
||||
#define PARENT_COLUMN 4
|
||||
#define STORAGE_COLUMN 5
|
||||
#define SIZE_COLUMN 6
|
||||
#define CREATED_COLUMN 7
|
||||
#define MODIFIED_COLUMN 8
|
||||
|
||||
#define TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
|
||||
"_id INTEGER PRIMARY KEY," \
|
||||
"path TEXT," \
|
||||
"format INTEGER," \
|
||||
"parent INTEGER," \
|
||||
"storage INTEGER," \
|
||||
"size INTEGER," \
|
||||
"date_created INTEGER," \
|
||||
"date_modified INTEGER" \
|
||||
");"
|
||||
|
||||
#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
|
||||
|
||||
#define FILE_ID_QUERY "SELECT _id FROM files WHERE path = ?;"
|
||||
#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
|
||||
|
||||
#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_created,date_modified FROM files WHERE _id = ?;"
|
||||
#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?,?);"
|
||||
#define FILE_DELETE "DELETE FROM files WHERE path = ?;"
|
||||
|
||||
|
||||
struct PropertyTableEntry {
|
||||
MtpObjectProperty property;
|
||||
int type;
|
||||
const char* columnName;
|
||||
};
|
||||
|
||||
static const PropertyTableEntry kPropertyTable[] = {
|
||||
{ MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
|
||||
{ MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
|
||||
{ MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
|
||||
{ MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
|
||||
{ MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
|
||||
{ MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR, "date_created" },
|
||||
{ MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
|
||||
};
|
||||
|
||||
static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
|
||||
int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
|
||||
const PropertyTableEntry* entry = kPropertyTable;
|
||||
for (int i = 0; i < count; i++, entry++) {
|
||||
if (entry->property == property) {
|
||||
type = entry->type;
|
||||
columnName = entry->columnName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MtpDatabase::MtpDatabase()
|
||||
: mFileIdQuery(NULL),
|
||||
mObjectInfoQuery(NULL),
|
||||
mFileInserter(NULL),
|
||||
mFileDeleter(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
MtpDatabase::~MtpDatabase() {
|
||||
}
|
||||
|
||||
bool MtpDatabase::open(const char* path, bool create) {
|
||||
if (!SqliteDatabase::open(path, create))
|
||||
return false;
|
||||
|
||||
// create the table if necessary
|
||||
if (!exec(TABLE_CREATE)) {
|
||||
fprintf(stderr, "could not create table\n");
|
||||
return false;
|
||||
}
|
||||
if (!exec(PATH_INDEX_CREATE)) {
|
||||
fprintf(stderr, "could not path index\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MtpObjectHandle MtpDatabase::addFile(const char* path,
|
||||
MtpObjectFormat format,
|
||||
MtpObjectHandle parent,
|
||||
MtpStorageID storage,
|
||||
uint64_t size,
|
||||
time_t created,
|
||||
time_t modified) {
|
||||
|
||||
// first check to see if the file exists
|
||||
if (mFileIdQuery)
|
||||
mFileIdQuery->reset();
|
||||
else {
|
||||
mFileIdQuery = new SqliteStatement(this);
|
||||
if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
|
||||
fprintf(stderr, "could not compile FILE_ID_QUERY\n");
|
||||
delete mFileIdQuery;
|
||||
mFileIdQuery = NULL;
|
||||
return kInvalidObjectHandle;
|
||||
}
|
||||
}
|
||||
|
||||
mFileIdQuery->bind(1, path);
|
||||
if (mFileIdQuery->step()) {
|
||||
int row = mFileIdQuery->getColumnInt(0);
|
||||
if (row > 0)
|
||||
return row;
|
||||
}
|
||||
|
||||
if (!mFileInserter) {
|
||||
mFileInserter = new SqliteStatement(this);
|
||||
if (!mFileInserter->prepare(FILE_INSERT)) {
|
||||
fprintf(stderr, "could not compile FILE_INSERT\n");
|
||||
delete mFileInserter;
|
||||
mFileInserter = NULL;
|
||||
return kInvalidObjectHandle;
|
||||
}
|
||||
}
|
||||
mFileInserter->bind(PATH_COLUMN, path);
|
||||
mFileInserter->bind(FORMAT_COLUMN, format);
|
||||
mFileInserter->bind(PARENT_COLUMN, parent);
|
||||
mFileInserter->bind(STORAGE_COLUMN, storage);
|
||||
mFileInserter->bind(SIZE_COLUMN, size);
|
||||
mFileInserter->bind(CREATED_COLUMN, created);
|
||||
mFileInserter->bind(MODIFIED_COLUMN, modified);
|
||||
mFileInserter->step();
|
||||
mFileInserter->reset();
|
||||
int row = lastInsertedRow();
|
||||
return (row > 0 ? row : kInvalidObjectHandle);
|
||||
}
|
||||
|
||||
MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
|
||||
MtpObjectFormat format,
|
||||
MtpObjectHandle parent) {
|
||||
bool whereStorage = (storageID != 0xFFFFFFFF);
|
||||
bool whereFormat = (format != 0);
|
||||
bool whereParent = (parent != 0);
|
||||
char intBuffer[20];
|
||||
|
||||
MtpString query("SELECT _id FROM files");
|
||||
if (whereStorage || whereFormat || whereParent)
|
||||
query += " WHERE";
|
||||
if (whereStorage) {
|
||||
snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
|
||||
query += " storage = ";
|
||||
query += intBuffer;
|
||||
}
|
||||
if (whereFormat) {
|
||||
snprintf(intBuffer, sizeof(intBuffer), "%d", format);
|
||||
if (whereStorage)
|
||||
query += " AND";
|
||||
query += " format = ";
|
||||
query += intBuffer;
|
||||
}
|
||||
if (whereParent) {
|
||||
snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
|
||||
if (whereStorage || whereFormat)
|
||||
query += " AND";
|
||||
query += " parent = ";
|
||||
query += intBuffer;
|
||||
}
|
||||
query += ";";
|
||||
|
||||
SqliteStatement stmt(this);
|
||||
printf("%s\n", (const char *)query);
|
||||
stmt.prepare(query);
|
||||
|
||||
MtpObjectHandleList* list = new MtpObjectHandleList();
|
||||
while (!stmt.isDone()) {
|
||||
if (stmt.step()) {
|
||||
int index = stmt.getColumnInt(0);
|
||||
printf("stmt.getColumnInt returned %d\n", index);
|
||||
if (index > 0)
|
||||
list->push(index);
|
||||
}
|
||||
}
|
||||
printf("list size: %d\n", list->size());
|
||||
return list;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
|
||||
MtpObjectProperty property,
|
||||
MtpDataPacket& packet) {
|
||||
int type;
|
||||
const char* columnName;
|
||||
char intBuffer[20];
|
||||
|
||||
if (!getPropertyInfo(property, type, columnName))
|
||||
return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
|
||||
snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
|
||||
|
||||
MtpString query("SELECT ");
|
||||
query += columnName;
|
||||
query += " FROM files WHERE _id = ";
|
||||
query += intBuffer;
|
||||
query += ";";
|
||||
|
||||
SqliteStatement stmt(this);
|
||||
printf("%s\n", (const char *)query);
|
||||
stmt.prepare(query);
|
||||
|
||||
if (!stmt.step())
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
|
||||
switch (type) {
|
||||
case MTP_TYPE_INT8:
|
||||
packet.putInt8(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_UINT8:
|
||||
packet.putUInt8(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_INT16:
|
||||
packet.putInt16(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_UINT16:
|
||||
packet.putUInt16(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_INT32:
|
||||
packet.putInt32(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_UINT32:
|
||||
packet.putUInt32(stmt.getColumnInt(0));
|
||||
break;
|
||||
case MTP_TYPE_INT64:
|
||||
packet.putInt64(stmt.getColumnInt64(0));
|
||||
break;
|
||||
case MTP_TYPE_UINT64:
|
||||
packet.putUInt64(stmt.getColumnInt64(0));
|
||||
break;
|
||||
case MTP_TYPE_STR:
|
||||
packet.putString(stmt.getColumnString(0));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unsupported object type\n");
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
}
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
|
||||
MtpDataPacket& packet) {
|
||||
char date[20];
|
||||
|
||||
if (mObjectInfoQuery)
|
||||
mObjectInfoQuery->reset();
|
||||
else {
|
||||
mObjectInfoQuery = new SqliteStatement(this);
|
||||
if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
|
||||
fprintf(stderr, "could not compile FILE_ID_QUERY\n");
|
||||
delete mObjectInfoQuery;
|
||||
mObjectInfoQuery = NULL;
|
||||
return MTP_RESPONSE_GENERAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
mObjectInfoQuery->bind(1, handle);
|
||||
if (!mObjectInfoQuery->step())
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
|
||||
MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
|
||||
MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
|
||||
MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
|
||||
// extract name from path. do we want a separate database entry for this?
|
||||
const char* name = mObjectInfoQuery->getColumnString(3);
|
||||
const char* lastSlash = strrchr(name, '/');
|
||||
if (lastSlash)
|
||||
name = lastSlash + 1;
|
||||
int64_t size = mObjectInfoQuery->getColumnInt64(4);
|
||||
time_t created = mObjectInfoQuery->getColumnInt(5);
|
||||
time_t modified = mObjectInfoQuery->getColumnInt(6);
|
||||
int associationType = (format == MTP_FORMAT_ASSOCIATION ?
|
||||
MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
|
||||
MTP_ASSOCIATION_TYPE_UNDEFINED);
|
||||
|
||||
printf("storageID: %d, format: %d, parent: %d\n", storageID, format, parent);
|
||||
|
||||
packet.putUInt32(storageID);
|
||||
packet.putUInt16(format);
|
||||
packet.putUInt16(0); // protection status
|
||||
packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
|
||||
packet.putUInt16(0); // thumb format
|
||||
packet.putUInt32(0); // thumb compressed size
|
||||
packet.putUInt32(0); // thumb pix width
|
||||
packet.putUInt32(0); // thumb pix height
|
||||
packet.putUInt32(0); // image pix width
|
||||
packet.putUInt32(0); // image pix height
|
||||
packet.putUInt32(0); // image bit depth
|
||||
packet.putUInt32(parent);
|
||||
packet.putUInt16(associationType);
|
||||
packet.putUInt32(0); // association desc
|
||||
packet.putUInt32(0); // sequence number
|
||||
packet.putString(name); // file name
|
||||
formatDateTime(created, date, sizeof(date));
|
||||
packet.putString(date); // date created
|
||||
formatDateTime(modified, date, sizeof(date));
|
||||
packet.putString(date); // date modified
|
||||
packet.putEmptyString(); // keywords
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
|
||||
MtpString& filePath,
|
||||
int64_t& fileLength) {
|
||||
if (mFilePathQuery)
|
||||
mFilePathQuery->reset();
|
||||
else {
|
||||
mFilePathQuery = new SqliteStatement(this);
|
||||
if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
|
||||
fprintf(stderr, "could not compile FILE_ID_QUERY\n");
|
||||
delete mFilePathQuery;
|
||||
mFilePathQuery = NULL;
|
||||
return kInvalidObjectHandle;
|
||||
}
|
||||
}
|
||||
|
||||
mFilePathQuery->bind(1, handle);
|
||||
if (!mFilePathQuery->step())
|
||||
return false;
|
||||
|
||||
const char* path = mFilePathQuery->getColumnString(0);
|
||||
if (!path)
|
||||
return false;
|
||||
filePath = path;
|
||||
fileLength = mFilePathQuery->getColumnInt64(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MtpDatabase::deleteFile(MtpObjectHandle handle) {
|
||||
if (!mFileDeleter) {
|
||||
mFileDeleter = new SqliteStatement(this);
|
||||
if (!mFileDeleter->prepare(FILE_DELETE)) {
|
||||
fprintf(stderr, "could not compile FILE_DELETE\n");
|
||||
delete mFileDeleter;
|
||||
mFileDeleter = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
printf("deleteFile %d\n", handle);
|
||||
mFileDeleter->bind(1, handle);
|
||||
mFileDeleter->step();
|
||||
mFileDeleter->reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
for getObjectPropDesc
|
||||
|
||||
packet.putUInt16(property);
|
||||
packet.putUInt16(dataType);
|
||||
packet.putUInt8(getSet);
|
||||
// default value DTS
|
||||
packet.putUInt32(groupCode);
|
||||
packet.putUInt8(formFlag);
|
||||
// form, variable
|
||||
*/
|
||||
65
media/mtp/MtpDatabase.h
Normal file
65
media/mtp/MtpDatabase.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_DATABASE_H
|
||||
#define _MTP_DATABASE_H
|
||||
|
||||
#include "MtpUtils.h"
|
||||
#include "SqliteDatabase.h"
|
||||
#include "mtp.h"
|
||||
|
||||
class MtpDataPacket;
|
||||
class SqliteStatement;
|
||||
|
||||
class MtpDatabase : public SqliteDatabase {
|
||||
private:
|
||||
SqliteStatement* mFileIdQuery;
|
||||
SqliteStatement* mFilePathQuery;
|
||||
SqliteStatement* mObjectInfoQuery;
|
||||
SqliteStatement* mFileInserter;
|
||||
SqliteStatement* mFileDeleter;
|
||||
|
||||
public:
|
||||
MtpDatabase();
|
||||
virtual ~MtpDatabase();
|
||||
|
||||
bool open(const char* path, bool create);
|
||||
MtpObjectHandle addFile(const char* path,
|
||||
MtpObjectFormat format,
|
||||
MtpObjectHandle parent,
|
||||
MtpStorageID storage,
|
||||
uint64_t size,
|
||||
time_t created,
|
||||
time_t modified);
|
||||
|
||||
MtpObjectHandleList* getObjectList(MtpStorageID storageID,
|
||||
MtpObjectFormat format,
|
||||
MtpObjectHandle parent);
|
||||
|
||||
MtpResponseCode getObjectProperty(MtpObjectHandle handle,
|
||||
MtpObjectProperty property,
|
||||
MtpDataPacket& packet);
|
||||
|
||||
MtpResponseCode getObjectInfo(MtpObjectHandle handle,
|
||||
MtpDataPacket& packet);
|
||||
|
||||
bool getObjectFilePath(MtpObjectHandle handle,
|
||||
MtpString& filePath,
|
||||
int64_t& fileLength);
|
||||
bool deleteFile(MtpObjectHandle handle);
|
||||
};
|
||||
|
||||
#endif // _MTP_DATABASE_H
|
||||
73
media/mtp/MtpDebug.cpp
Normal file
73
media/mtp/MtpDebug.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MtpDebug.h"
|
||||
|
||||
|
||||
struct OperationCodeEntry {
|
||||
const char* name;
|
||||
MtpOperationCode code;
|
||||
};
|
||||
|
||||
static const OperationCodeEntry 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_REFERENCES", 0x9810 },
|
||||
{ "MTP_OPERATION_SET_OBJECT_REFERENCES", 0x9811 },
|
||||
{ "MTP_OPERATION_SKIP", 0x9820 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
|
||||
const char* MtpDebug::getOperationCodeName(MtpOperationCode code) {
|
||||
const OperationCodeEntry* entry = sOperationCodes;
|
||||
while (entry->name) {
|
||||
if (entry->code == code)
|
||||
return entry->name;
|
||||
entry++;
|
||||
}
|
||||
return "*** UNKNOWN OPERATION ***";
|
||||
}
|
||||
27
media/mtp/MtpDebug.h
Normal file
27
media/mtp/MtpDebug.h
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_DEBUG_H
|
||||
#define _MTP_DEBUG_H
|
||||
|
||||
#include "mtp.h"
|
||||
|
||||
class MtpDebug {
|
||||
public:
|
||||
static const char* getOperationCodeName(MtpOperationCode code);
|
||||
};
|
||||
|
||||
#endif // _MTP_DEBUG_H
|
||||
136
media/mtp/MtpPacket.cpp
Normal file
136
media/mtp/MtpPacket.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <usbhost/usbhost.h>
|
||||
|
||||
#include "MtpPacket.h"
|
||||
|
||||
MtpPacket::MtpPacket(int bufferSize)
|
||||
: mBuffer(NULL),
|
||||
mBufferSize(bufferSize),
|
||||
mAllocationIncrement(bufferSize),
|
||||
mPacketSize(0)
|
||||
{
|
||||
mBuffer = (uint8_t *)malloc(bufferSize);
|
||||
if (!mBuffer) {
|
||||
fprintf(stderr, "out of memory!\n");
|
||||
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) {
|
||||
fprintf(stderr, "out of memory!\n");
|
||||
abort();
|
||||
}
|
||||
mBufferSize = newLength;
|
||||
}
|
||||
}
|
||||
|
||||
void MtpPacket::dump() {
|
||||
for (int i = 0; i < mPacketSize; i++) {
|
||||
printf("%02X ", mBuffer[i]);
|
||||
if (i % 16 == 15)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "index %d out of range in MtpRequestPacket::getParameter\n", 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) {
|
||||
fprintf(stderr, "index %d out of range in MtpResponsePacket::setParameter\n", 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_endpoint *ep, void* buffer, int length) {
|
||||
printf("MtpPacket::transfer length: %d\n", length);
|
||||
if (usb_endpoint_queue(ep, buffer, length)) {
|
||||
printf("usb_endpoint_queue failed, errno: %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
int ep_num;
|
||||
return usb_endpoint_wait(usb_endpoint_get_device(ep), &ep_num);
|
||||
}
|
||||
#endif
|
||||
68
media/mtp/MtpPacket.h
Normal file
68
media/mtp/MtpPacket.h
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_PACKET_H
|
||||
#define _MTP_PACKET_H
|
||||
|
||||
class MtpStringBuffer;
|
||||
|
||||
#include "mtp.h"
|
||||
#include "MtpUtils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class MtpPacket {
|
||||
|
||||
protected:
|
||||
uint8_t* mBuffer;
|
||||
// current size of the buffer
|
||||
int mBufferSize;
|
||||
// number of bytes to add when resizing the buffer
|
||||
int mAllocationIncrement;
|
||||
// size of the data in the packet
|
||||
int mPacketSize;
|
||||
|
||||
public:
|
||||
MtpPacket(int bufferSize);
|
||||
virtual ~MtpPacket();
|
||||
|
||||
// sets packet size to the default container size and sets buffer to zero
|
||||
virtual void reset();
|
||||
|
||||
void allocate(int length);
|
||||
void dump();
|
||||
|
||||
uint16_t getContainerCode() const;
|
||||
void setContainerCode(uint16_t code);
|
||||
|
||||
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_endpoint *ep, void* buffer, int length);
|
||||
#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
|
||||
50
media/mtp/MtpRequestPacket.cpp
Normal file
50
media/mtp/MtpRequestPacket.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "MtpRequestPacket.h"
|
||||
|
||||
MtpRequestPacket::MtpRequestPacket()
|
||||
: MtpPacket(512)
|
||||
{
|
||||
}
|
||||
|
||||
MtpRequestPacket::~MtpRequestPacket() {
|
||||
}
|
||||
|
||||
#ifdef MTP_DEVICE
|
||||
int MtpRequestPacket::read(int fd) {
|
||||
int ret = ::read(fd, mBuffer, mBufferSize);
|
||||
if (ret >= 0)
|
||||
mPacketSize = ret;
|
||||
else
|
||||
mPacketSize = 0;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MTP_HOST
|
||||
// write our buffer to the given endpoint (host mode)
|
||||
int MtpRequestPacket::write(struct usb_endpoint *ep)
|
||||
{
|
||||
putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
|
||||
putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_COMMAND);
|
||||
return transfer(ep, mBuffer, mPacketSize);
|
||||
}
|
||||
#endif
|
||||
44
media/mtp/MtpRequestPacket.h
Normal file
44
media/mtp/MtpRequestPacket.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_REQUEST_PACKET_H
|
||||
#define _MTP_REQUEST_PACKET_H
|
||||
|
||||
#include "MtpPacket.h"
|
||||
#include "mtp.h"
|
||||
|
||||
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_endpoint *ep);
|
||||
#endif
|
||||
|
||||
inline MtpOperationCode getOperationCode() const { return getContainerCode(); }
|
||||
inline void setOperationCode(MtpOperationCode code)
|
||||
{ return setContainerCode(code); }
|
||||
};
|
||||
|
||||
#endif // _MTP_REQUEST_PACKET_H
|
||||
52
media/mtp/MtpResponsePacket.cpp
Normal file
52
media/mtp/MtpResponsePacket.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "MtpResponsePacket.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
|
||||
// read our buffer from the given endpoint
|
||||
int MtpResponsePacket::read(struct usb_endpoint *ep) {
|
||||
int ret = transfer(ep, mBuffer, mBufferSize);
|
||||
if (ret >= 0)
|
||||
mPacketSize = ret;
|
||||
else
|
||||
mPacketSize = 0;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
44
media/mtp/MtpResponsePacket.h
Normal file
44
media/mtp/MtpResponsePacket.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_RESPONSE_PACKET_H
|
||||
#define _MTP_RESPONSE_PACKET_H
|
||||
|
||||
#include "MtpPacket.h"
|
||||
#include "mtp.h"
|
||||
|
||||
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 from the given endpoint
|
||||
int read(struct usb_endpoint *ep);
|
||||
#endif
|
||||
|
||||
inline MtpResponseCode getResponseCode() const { return getContainerCode(); }
|
||||
inline void setResponseCode(MtpResponseCode code)
|
||||
{ return setContainerCode(code); }
|
||||
};
|
||||
|
||||
#endif // _MTP_RESPONSE_PACKET_H
|
||||
516
media/mtp/MtpServer.cpp
Normal file
516
media/mtp/MtpServer.cpp
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "MtpDebug.h"
|
||||
#include "MtpServer.h"
|
||||
#include "MtpStorage.h"
|
||||
#include "MtpStringBuffer.h"
|
||||
#include "MtpDatabase.h"
|
||||
|
||||
#include "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_REFERENCES,
|
||||
// MTP_OPERATION_SET_OBJECT_REFERENCES,
|
||||
// MTP_OPERATION_SKIP,
|
||||
};
|
||||
|
||||
static const MtpObjectProperty kSupportedObjectProperties[] = {
|
||||
MTP_PROPERTY_STORAGE_ID,
|
||||
MTP_PROPERTY_OBJECT_FORMAT,
|
||||
MTP_PROPERTY_OBJECT_SIZE,
|
||||
MTP_PROPERTY_OBJECT_FILE_NAME,
|
||||
MTP_PROPERTY_PARENT_OBJECT,
|
||||
};
|
||||
|
||||
static const MtpObjectFormat kSupportedPlaybackFormats[] = {
|
||||
// FIXME - fill this out later
|
||||
MTP_FORMAT_ASSOCIATION,
|
||||
MTP_FORMAT_MP3,
|
||||
};
|
||||
|
||||
MtpServer::MtpServer(int fd, const char* databasePath)
|
||||
: mFD(fd),
|
||||
mDatabasePath(databasePath),
|
||||
mDatabase(NULL),
|
||||
mSessionID(0),
|
||||
mSessionOpen(false),
|
||||
mSendObjectHandle(kInvalidObjectHandle),
|
||||
mSendObjectFileSize(0)
|
||||
{
|
||||
mDatabase = new MtpDatabase();
|
||||
mDatabase->open(databasePath, true);
|
||||
}
|
||||
|
||||
MtpServer::~MtpServer() {
|
||||
}
|
||||
|
||||
void MtpServer::addStorage(const char* filePath) {
|
||||
int index = mStorages.size() + 1;
|
||||
index |= index << 16; // set high and low part to our index
|
||||
MtpStorage* storage = new MtpStorage(index, filePath, mDatabase);
|
||||
addStorage(storage);
|
||||
}
|
||||
|
||||
MtpStorage* MtpServer::getStorage(MtpStorageID id) {
|
||||
for (int i = 0; i < mStorages.size(); i++) {
|
||||
MtpStorage* storage = mStorages[i];
|
||||
if (storage->getStorageID() == id)
|
||||
return storage;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MtpServer::scanStorage() {
|
||||
for (int i = 0; i < mStorages.size(); i++) {
|
||||
MtpStorage* storage = mStorages[i];
|
||||
storage->scanFiles();
|
||||
}
|
||||
}
|
||||
|
||||
void MtpServer::run() {
|
||||
int fd = mFD;
|
||||
|
||||
printf("MtpServer::run fd: %d\n", fd);
|
||||
|
||||
while (1) {
|
||||
int ret = mRequest.read(fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "request read returned %d, errno: %d\n", ret, errno);
|
||||
break;
|
||||
}
|
||||
MtpOperationCode operation = mRequest.getOperationCode();
|
||||
MtpTransactionID transaction = mRequest.getTransactionID();
|
||||
|
||||
printf("operation: %s\n", MtpDebug::getOperationCodeName(operation));
|
||||
mRequest.dump();
|
||||
|
||||
// FIXME need to generalize this
|
||||
bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO);
|
||||
if (dataIn) {
|
||||
int ret = mData.read(fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "data read returned %d, errno: %d\n", ret, errno);
|
||||
break;
|
||||
}
|
||||
printf("received data:\n");
|
||||
mData.dump();
|
||||
} else {
|
||||
mData.reset();
|
||||
}
|
||||
|
||||
handleRequest();
|
||||
|
||||
if (!dataIn && mData.hasData()) {
|
||||
mData.setOperationCode(operation);
|
||||
mData.setTransactionID(transaction);
|
||||
printf("sending data:\n");
|
||||
mData.dump();
|
||||
ret = mData.write(fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mResponse.setTransactionID(transaction);
|
||||
ret = mResponse.write(fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "request write returned %d, errno: %d\n", ret, errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MtpServer::handleRequest() {
|
||||
MtpOperationCode operation = mRequest.getOperationCode();
|
||||
MtpResponseCode response;
|
||||
|
||||
mResponse.reset();
|
||||
|
||||
if (mSendObjectHandle != kInvalidObjectHandle && operation != MTP_OPERATION_SEND_OBJECT) {
|
||||
// FIXME - need to delete mSendObjectHandle from the database
|
||||
fprintf(stderr, "expected SendObject after SendObjectInfo\n");
|
||||
mSendObjectHandle = kInvalidObjectHandle;
|
||||
}
|
||||
|
||||
switch (operation) {
|
||||
case MTP_OPERATION_GET_DEVICE_INFO:
|
||||
response = doGetDeviceInfo();
|
||||
break;
|
||||
case MTP_OPERATION_OPEN_SESSION:
|
||||
response = doOpenSession();
|
||||
break;
|
||||
case MTP_OPERATION_CLOSE_SESSION:
|
||||
response = doCloseSession();
|
||||
break;
|
||||
case MTP_OPERATION_GET_STORAGE_IDS:
|
||||
response = doGetStorageIDs();
|
||||
break;
|
||||
case MTP_OPERATION_GET_STORAGE_INFO:
|
||||
response = doGetStorageInfo();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED:
|
||||
response = doGetObjectPropsSupported();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT_HANDLES:
|
||||
response = doGetObjectHandles();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT_PROP_VALUE:
|
||||
response = doGetObjectPropValue();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT_INFO:
|
||||
response = doGetObjectInfo();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT:
|
||||
response = doGetObject();
|
||||
break;
|
||||
case MTP_OPERATION_SEND_OBJECT_INFO:
|
||||
response = doSendObjectInfo();
|
||||
break;
|
||||
case MTP_OPERATION_SEND_OBJECT:
|
||||
response = doSendObject();
|
||||
break;
|
||||
case MTP_OPERATION_DELETE_OBJECT:
|
||||
response = doDeleteObject();
|
||||
break;
|
||||
case MTP_OPERATION_GET_OBJECT_PROP_DESC:
|
||||
default:
|
||||
response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
mResponse.setResponseCode(response);
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetDeviceInfo() {
|
||||
MtpStringBuffer string;
|
||||
|
||||
// fill in device info
|
||||
mData.putUInt16(MTP_STANDARD_VERSION);
|
||||
mData.putUInt32(6); // MTP Vendor Extension ID
|
||||
mData.putUInt16(MTP_STANDARD_VERSION);
|
||||
string.set("microsoft.com: 1.0;");
|
||||
mData.putString(string); // MTP Extensions
|
||||
mData.putUInt16(0); //Functional Mode
|
||||
mData.putAUInt16(kSupportedOperationCodes,
|
||||
sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
|
||||
mData.putEmptyArray(); // Events Supported
|
||||
mData.putEmptyArray(); // Device Properties Supported
|
||||
mData.putEmptyArray(); // Capture Formats
|
||||
mData.putAUInt16(kSupportedPlaybackFormats,
|
||||
sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
|
||||
// FIXME
|
||||
string.set("Google, Inc.");
|
||||
mData.putString(string); // Manufacturer
|
||||
string.set("Just an Ordinary MTP Device");
|
||||
mData.putString(string); // Model
|
||||
string.set("1.0");
|
||||
mData.putString(string); // Device Version
|
||||
string.set("123456789012345678AA");
|
||||
mData.putString(string); // Serial Number
|
||||
|
||||
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;
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doCloseSession() {
|
||||
if (!mSessionOpen)
|
||||
return MTP_RESPONSE_SESSION_NOT_OPEN;
|
||||
mSessionID = 0;
|
||||
mSessionOpen = false;
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetStorageIDs() {
|
||||
if (!mSessionOpen)
|
||||
return MTP_RESPONSE_SESSION_NOT_OPEN;
|
||||
|
||||
int count = mStorages.size();
|
||||
mData.putUInt32(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
mData.putUInt32(mStorages[i]->getStorageID());
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetStorageInfo() {
|
||||
MtpStringBuffer string;
|
||||
|
||||
if (!mSessionOpen)
|
||||
return MTP_RESPONSE_SESSION_NOT_OPEN;
|
||||
MtpStorageID id = mRequest.getParameter(1);
|
||||
MtpStorage* storage = getStorage(id);
|
||||
if (!storage)
|
||||
return MTP_RESPONSE_INVALID_STORAGE_ID;
|
||||
|
||||
mData.putUInt16(storage->getType());
|
||||
mData.putUInt16(storage->getFileSystemType());
|
||||
mData.putUInt16(storage->getAccessCapability());
|
||||
mData.putUInt64(storage->getMaxCapacity());
|
||||
mData.putUInt64(storage->getFreeSpace());
|
||||
mData.putUInt32(1024*1024*1024); // Free Space in Objects
|
||||
string.set(storage->getDescription());
|
||||
mData.putString(string);
|
||||
mData.putEmptyString(); // Volume Identifier
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetObjectPropsSupported() {
|
||||
if (!mSessionOpen)
|
||||
return MTP_RESPONSE_SESSION_NOT_OPEN;
|
||||
MtpObjectFormat format = mRequest.getParameter(1);
|
||||
mData.putAUInt16(kSupportedObjectProperties,
|
||||
sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
|
||||
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); // 0x00000000 for all formats
|
||||
MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
|
||||
// 0x00000000 for all objects?
|
||||
|
||||
MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
|
||||
mData.putAUInt32(handles);
|
||||
delete handles;
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetObjectPropValue() {
|
||||
MtpObjectHandle handle = mRequest.getParameter(1);
|
||||
MtpObjectProperty property = mRequest.getParameter(2);
|
||||
|
||||
return mDatabase->getObjectProperty(handle, property, mData);
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetObjectInfo() {
|
||||
MtpObjectHandle handle = mRequest.getParameter(1);
|
||||
return mDatabase->getObjectInfo(handle, mData);
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetObject() {
|
||||
MtpObjectHandle handle = mRequest.getParameter(1);
|
||||
MtpString filePath;
|
||||
int64_t fileLength;
|
||||
if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
|
||||
mtp_file_range mfr;
|
||||
mfr.path = filePath;
|
||||
mfr.path_length = strlen(mfr.path);
|
||||
mfr.offset = 0;
|
||||
mfr.length = fileLength;
|
||||
|
||||
// send data header
|
||||
mData.setOperationCode(mRequest.getOperationCode());
|
||||
mData.setTransactionID(mRequest.getTransactionID());
|
||||
mData.writeDataHeader(mFD, fileLength);
|
||||
|
||||
// then transfer the file
|
||||
int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
|
||||
// FIXME - check for errors here
|
||||
printf("MTP_SEND_FILE returned %d\n", ret);
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doSendObjectInfo() {
|
||||
MtpString path;
|
||||
MtpStorageID storageID = mRequest.getParameter(1);
|
||||
MtpStorage* storage = getStorage(storageID);
|
||||
MtpObjectHandle parent = mRequest.getParameter(2);
|
||||
if (!storage)
|
||||
return MTP_RESPONSE_INVALID_STORAGE_ID;
|
||||
|
||||
// special case the root
|
||||
if (parent == MTP_PARENT_ROOT)
|
||||
path = storage->getPath();
|
||||
else {
|
||||
int64_t dummy;
|
||||
if (!mDatabase->getObjectFilePath(parent, path, dummy))
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
time_t createdTime, modifiedTime;
|
||||
if (!parseDateTime(created, createdTime))
|
||||
createdTime = 0;
|
||||
if (!parseDateTime(modified, modifiedTime))
|
||||
modifiedTime = 0;
|
||||
printf("SendObjectInfo format: %04X size: %d name: %s, created: %s, modified: %s\n",
|
||||
format, mSendObjectFileSize, (const char*)name, (const char*)created, (const char*)modified);
|
||||
|
||||
if (path[path.size() - 1] != '/')
|
||||
path += "/";
|
||||
path += (const char *)name;
|
||||
|
||||
MtpObjectHandle handle = mDatabase->addFile((const char*)path,
|
||||
format, parent, storageID, mSendObjectFileSize,
|
||||
createdTime, modifiedTime);
|
||||
if (handle == kInvalidObjectHandle)
|
||||
return MTP_RESPONSE_GENERAL_ERROR;
|
||||
|
||||
if (format == MTP_FORMAT_ASSOCIATION) {
|
||||
mode_t mask = umask(0);
|
||||
int ret = mkdir((const char *)path, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
umask(mask);
|
||||
if (ret && ret != -EEXIST)
|
||||
return MTP_RESPONSE_GENERAL_ERROR;
|
||||
} else {
|
||||
mSendObjectFilePath = path;
|
||||
// save the handle for the SendObject call, which should follow
|
||||
mSendObjectHandle = handle;
|
||||
}
|
||||
|
||||
mResponse.setParameter(1, storageID);
|
||||
mResponse.setParameter(2, parent);
|
||||
mResponse.setParameter(3, handle);
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doSendObject() {
|
||||
if (mSendObjectHandle == kInvalidObjectHandle) {
|
||||
fprintf(stderr, "Expected SendObjectInfo before SendObject\n");
|
||||
return MTP_RESPONSE_NO_VALID_OBJECT_INFO;
|
||||
}
|
||||
|
||||
// read the header
|
||||
int ret = mData.readDataHeader(mFD);
|
||||
// FIXME - check for errors here.
|
||||
|
||||
// reset so we don't attempt to send this back
|
||||
mData.reset();
|
||||
|
||||
mtp_file_range mfr;
|
||||
mfr.path = (const char*)mSendObjectFilePath;
|
||||
mfr.path_length = strlen(mfr.path);
|
||||
mfr.offset = 0;
|
||||
mfr.length = mSendObjectFileSize;
|
||||
|
||||
// transfer the file
|
||||
ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
|
||||
// FIXME - check for errors here.
|
||||
// we need to return a reasonable response and delete
|
||||
// mSendObjectHandle from the database if this fails.
|
||||
printf("MTP_RECEIVE_FILE returned %d\n", ret);
|
||||
|
||||
mSendObjectHandle = kInvalidObjectHandle;
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doDeleteObject() {
|
||||
MtpObjectHandle handle = mRequest.getParameter(1);
|
||||
MtpObjectFormat format = mRequest.getParameter(1);
|
||||
// FIXME - support deleting all objects if handle is 0xFFFFFFFF
|
||||
// FIXME - implement deleting objects by format
|
||||
// FIXME - handle non-empty directories
|
||||
|
||||
MtpString filePath;
|
||||
int64_t fileLength;
|
||||
if (!mDatabase->getObjectFilePath(handle, filePath, fileLength))
|
||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||
|
||||
printf("deleting %s\n", (const char *)filePath);
|
||||
// one of these should work
|
||||
rmdir((const char *)filePath);
|
||||
unlink((const char *)filePath);
|
||||
|
||||
mDatabase->deleteFile(handle);
|
||||
|
||||
return MTP_RESPONSE_OK;
|
||||
}
|
||||
|
||||
MtpResponseCode MtpServer::doGetObjectPropDesc() {
|
||||
MtpObjectProperty property = mRequest.getParameter(1);
|
||||
MtpObjectFormat format = mRequest.getParameter(2);
|
||||
|
||||
return -1;
|
||||
}
|
||||
86
media/mtp/MtpServer.h
Normal file
86
media/mtp/MtpServer.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_SERVER_H
|
||||
#define _MTP_SERVER_H
|
||||
|
||||
#include "MtpRequestPacket.h"
|
||||
#include "MtpDataPacket.h"
|
||||
#include "MtpResponsePacket.h"
|
||||
#include "mtp.h"
|
||||
|
||||
#include "MtpUtils.h"
|
||||
|
||||
class MtpStorage;
|
||||
class MtpDatabase;
|
||||
|
||||
class MtpServer {
|
||||
|
||||
private:
|
||||
// file descriptor for MTP kernel driver
|
||||
int mFD;
|
||||
|
||||
// path to our sqlite3 database
|
||||
const char* mDatabasePath;
|
||||
|
||||
MtpDatabase* mDatabase;
|
||||
|
||||
// current session ID
|
||||
MtpSessionID mSessionID;
|
||||
// true if we have an open session and mSessionID is valid
|
||||
bool mSessionOpen;
|
||||
|
||||
MtpRequestPacket mRequest;
|
||||
MtpDataPacket mData;
|
||||
MtpResponsePacket mResponse;
|
||||
|
||||
MtpStorageList mStorages;
|
||||
|
||||
// handle for new object, set by SendObjectInfo and used by SendObject
|
||||
MtpObjectHandle mSendObjectHandle;
|
||||
MtpString mSendObjectFilePath;
|
||||
size_t mSendObjectFileSize;
|
||||
|
||||
public:
|
||||
MtpServer(int fd, const char* databasePath);
|
||||
virtual ~MtpServer();
|
||||
|
||||
void addStorage(const char* filePath);
|
||||
inline void addStorage(MtpStorage* storage) { mStorages.push(storage); }
|
||||
MtpStorage* getStorage(MtpStorageID id);
|
||||
void scanStorage();
|
||||
void run();
|
||||
|
||||
private:
|
||||
void handleRequest();
|
||||
|
||||
MtpResponseCode doGetDeviceInfo();
|
||||
MtpResponseCode doOpenSession();
|
||||
MtpResponseCode doCloseSession();
|
||||
MtpResponseCode doGetStorageIDs();
|
||||
MtpResponseCode doGetStorageInfo();
|
||||
MtpResponseCode doGetObjectPropsSupported();
|
||||
MtpResponseCode doGetObjectHandles();
|
||||
MtpResponseCode doGetObjectPropValue();
|
||||
MtpResponseCode doGetObjectInfo();
|
||||
MtpResponseCode doGetObject();
|
||||
MtpResponseCode doSendObjectInfo();
|
||||
MtpResponseCode doSendObject();
|
||||
MtpResponseCode doDeleteObject();
|
||||
MtpResponseCode doGetObjectPropDesc();
|
||||
};
|
||||
|
||||
#endif // _MTP_SERVER_H
|
||||
135
media/mtp/MtpStorage.cpp
Normal file
135
media/mtp/MtpStorage.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MtpDatabase.h"
|
||||
#include "MtpStorage.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>
|
||||
|
||||
|
||||
MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, MtpDatabase* db)
|
||||
: mStorageID(id),
|
||||
mFilePath(filePath),
|
||||
mDatabase(db),
|
||||
mMaxCapacity(0)
|
||||
{
|
||||
}
|
||||
|
||||
MtpStorage::~MtpStorage() {
|
||||
}
|
||||
|
||||
int MtpStorage::getType() const {
|
||||
return 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(mFilePath, &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(mFilePath, &stat))
|
||||
return -1;
|
||||
return (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
|
||||
}
|
||||
|
||||
const char* MtpStorage::getDescription() const {
|
||||
return "Phone Storage";
|
||||
}
|
||||
|
||||
bool MtpStorage::scanFiles() {
|
||||
mDatabase->beginTransaction();
|
||||
int ret = scanDirectory(mFilePath, MTP_PARENT_ROOT);
|
||||
mDatabase->commitTransaction();
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
int MtpStorage::scanDirectory(const char* path, MtpObjectHandle parent)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
struct dirent* entry;
|
||||
|
||||
int length = strlen(path);
|
||||
if (length > sizeof(buffer) + 2) {
|
||||
fprintf(stderr, "path too long: %s\n", path);
|
||||
}
|
||||
|
||||
DIR* dir = opendir(path);
|
||||
if (!dir) {
|
||||
fprintf(stderr, "opendir %s failed, errno: %d", path, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(buffer, path, sizeof(buffer));
|
||||
char* fileStart = buffer + length;
|
||||
// make sure we have a trailing slash
|
||||
if (fileStart[-1] != '/') {
|
||||
*(fileStart++) = '/';
|
||||
}
|
||||
int fileNameLength = sizeof(buffer) + fileStart - buffer;
|
||||
|
||||
while ((entry = readdir(dir))) {
|
||||
const char* name = entry->d_name;
|
||||
|
||||
// ignore "." and "..", as well as any files or directories staring with dot
|
||||
if (name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (strlen(name) + 1 > fileNameLength) {
|
||||
fprintf(stderr, "path too long for %s\n", name);
|
||||
continue;
|
||||
}
|
||||
strcpy(fileStart, name);
|
||||
|
||||
struct stat statbuf;
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
stat(buffer, &statbuf);
|
||||
|
||||
if (entry->d_type == DT_DIR) {
|
||||
MtpObjectHandle handle = mDatabase->addFile(buffer, MTP_FORMAT_ASSOCIATION,
|
||||
parent, mStorageID, 0, 0, statbuf.st_mtime);
|
||||
scanDirectory(buffer, handle);
|
||||
} else if (entry->d_type == DT_REG) {
|
||||
mDatabase->addFile(buffer, MTP_FORMAT_UNDEFINED, parent, mStorageID,
|
||||
statbuf.st_size, 0, statbuf.st_mtime);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
52
media/mtp/MtpStorage.h
Normal file
52
media/mtp/MtpStorage.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_STORAGE_H
|
||||
#define _MTP_STORAGE_H
|
||||
|
||||
#include "mtp.h"
|
||||
|
||||
class MtpDatabase;
|
||||
class SqliteStatement;
|
||||
|
||||
class MtpStorage {
|
||||
|
||||
private:
|
||||
MtpStorageID mStorageID;
|
||||
const char* mFilePath;
|
||||
MtpDatabase* mDatabase;
|
||||
uint64_t mMaxCapacity;
|
||||
|
||||
public:
|
||||
MtpStorage(MtpStorageID id, const char* filePath, MtpDatabase* db);
|
||||
virtual ~MtpStorage();
|
||||
|
||||
inline MtpStorageID getStorageID() const { return mStorageID; }
|
||||
int getType() const;
|
||||
int getFileSystemType() const;
|
||||
int getAccessCapability() const;
|
||||
uint64_t getMaxCapacity();
|
||||
uint64_t getFreeSpace();
|
||||
const char* getDescription() const;
|
||||
inline const char* getPath() const { return mFilePath; }
|
||||
|
||||
bool scanFiles();
|
||||
|
||||
private:
|
||||
int scanDirectory(const char* path, MtpObjectHandle parent);
|
||||
};
|
||||
|
||||
#endif // _MTP_STORAGE_H
|
||||
133
media/mtp/MtpStringBuffer.cpp
Normal file
133
media/mtp/MtpStringBuffer.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <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 MtpStringBuffer& src)
|
||||
: mCharCount(src.mCharCount),
|
||||
mByteCount(src.mByteCount)
|
||||
{
|
||||
memcpy(mBuffer, src.mBuffer, mByteCount);
|
||||
}
|
||||
|
||||
|
||||
MtpStringBuffer::~MtpStringBuffer() {
|
||||
}
|
||||
|
||||
void MtpStringBuffer::set(const char* src) {
|
||||
int length = strlen(src);
|
||||
if (length >= sizeof(mBuffer))
|
||||
length = sizeof(mBuffer) - 1;
|
||||
memcpy(mBuffer, src, length);
|
||||
|
||||
// count the characters
|
||||
int count = 0;
|
||||
char ch;
|
||||
while ((ch = *src++) != 0) {
|
||||
if ((ch & 0x80) == 0) {
|
||||
// single byte character
|
||||
} else if ((ch & 0xE0) == 0xC0) {
|
||||
// two byte character
|
||||
if (! *src++) {
|
||||
// last character was truncated, so ignore last byte
|
||||
length--;
|
||||
break;
|
||||
}
|
||||
} else if ((ch & 0xF0) == 0xE0) {
|
||||
// 3 byte char
|
||||
if (! *src++) {
|
||||
// last character was truncated, so ignore last byte
|
||||
length--;
|
||||
break;
|
||||
}
|
||||
if (! *src++) {
|
||||
// last character was truncated, so ignore last two bytes
|
||||
length -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
mByteCount = length + 1;
|
||||
mBuffer[length] = 0;
|
||||
mCharCount = count;
|
||||
}
|
||||
|
||||
void MtpStringBuffer::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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
50
media/mtp/MtpStringBuffer.h
Normal file
50
media/mtp/MtpStringBuffer.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_STRING_BUFFER_H
|
||||
#define _MTP_STRING_BUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class MtpDataPacket;
|
||||
|
||||
// Represents a utf8 string, with a maximum of 255 characters
|
||||
class MtpStringBuffer {
|
||||
|
||||
private:
|
||||
// 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 MtpStringBuffer& src);
|
||||
virtual ~MtpStringBuffer();
|
||||
|
||||
void set(const char* 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
|
||||
73
media/mtp/MtpUtils.cpp
Normal file
73
media/mtp/MtpUtils.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <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;
|
||||
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, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
|
||||
|
||||
34
media/mtp/MtpUtils.h
Normal file
34
media/mtp/MtpUtils.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_UTILS_H
|
||||
#define _MTP_UTILS_H
|
||||
|
||||
#include "utils/String8.h"
|
||||
#include "utils/Vector.h"
|
||||
|
||||
class MtpStorage;
|
||||
|
||||
typedef android::Vector<MtpStorage *> MtpStorageList;
|
||||
typedef android::Vector<uint32_t> UInt32List;
|
||||
typedef UInt32List MtpObjectHandleList;
|
||||
|
||||
typedef android::String8 MtpString;
|
||||
|
||||
bool parseDateTime(const char* dateTime, time_t& outSeconds);
|
||||
void formatDateTime(time_t seconds, char* buffer, int bufferLength);
|
||||
|
||||
#endif // _MTP_UTILS_H
|
||||
81
media/mtp/SqliteDatabase.cpp
Normal file
81
media/mtp/SqliteDatabase.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SqliteDatabase.h"
|
||||
#include "SqliteStatement.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
SqliteDatabase::SqliteDatabase()
|
||||
: mDatabaseHandle(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
SqliteDatabase::~SqliteDatabase() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool SqliteDatabase::open(const char* path, bool create) {
|
||||
int flags = SQLITE_OPEN_READWRITE;
|
||||
if (create) flags |= SQLITE_OPEN_CREATE;
|
||||
// SQLITE_OPEN_NOMUTEX?
|
||||
int ret = sqlite3_open_v2(path, &mDatabaseHandle, flags, NULL);
|
||||
if (ret) {
|
||||
fprintf(stderr, "could not open database\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SqliteDatabase::close() {
|
||||
if (mDatabaseHandle) {
|
||||
sqlite3_close(mDatabaseHandle);
|
||||
mDatabaseHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool SqliteDatabase::exec(const char* sql) {
|
||||
return (sqlite3_exec(mDatabaseHandle, sql, NULL, NULL, NULL) == 0);
|
||||
}
|
||||
|
||||
int SqliteDatabase::lastInsertedRow() {
|
||||
return sqlite3_last_insert_rowid(mDatabaseHandle);
|
||||
}
|
||||
|
||||
void SqliteDatabase::beginTransaction() {
|
||||
exec("BEGIN TRANSACTION");
|
||||
}
|
||||
|
||||
void SqliteDatabase::commitTransaction() {
|
||||
exec("COMMIT TRANSACTION");
|
||||
}
|
||||
|
||||
void SqliteDatabase::rollbackTransaction() {
|
||||
exec("ROLLBACK TRANSACTION");
|
||||
}
|
||||
|
||||
int SqliteDatabase::getVersion() {
|
||||
SqliteStatement stmt(this);
|
||||
stmt.prepare("PRAGMA user_version;");
|
||||
stmt.step();
|
||||
return stmt.getColumnInt(0);
|
||||
}
|
||||
void SqliteDatabase::setVersion(int version) {
|
||||
char buffer[40];
|
||||
snprintf(buffer, sizeof(buffer), "PRAGMA user_version = %d", version);
|
||||
exec(buffer);
|
||||
}
|
||||
47
media/mtp/SqliteDatabase.h
Normal file
47
media/mtp/SqliteDatabase.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _SQLITE_DATABASE_H
|
||||
#define _SQLITE_DATABASE_H
|
||||
|
||||
typedef struct sqlite3 sqlite3;
|
||||
|
||||
class SqliteDatabase {
|
||||
private:
|
||||
sqlite3* mDatabaseHandle;
|
||||
|
||||
public:
|
||||
SqliteDatabase();
|
||||
virtual ~SqliteDatabase();
|
||||
|
||||
virtual bool open(const char* path, bool create);
|
||||
virtual void close();
|
||||
|
||||
bool exec(const char* sql);
|
||||
int lastInsertedRow();
|
||||
|
||||
void beginTransaction();
|
||||
void commitTransaction();
|
||||
void rollbackTransaction();
|
||||
|
||||
int getVersion();
|
||||
void setVersion(int version);
|
||||
|
||||
inline sqlite3* getDatabaseHandle() const { return mDatabaseHandle; }
|
||||
|
||||
};
|
||||
|
||||
#endif // _SQLITE_DATABASE_H
|
||||
77
media/mtp/SqliteStatement.cpp
Normal file
77
media/mtp/SqliteStatement.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SqliteStatement.h"
|
||||
#include "SqliteDatabase.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
SqliteStatement::SqliteStatement(SqliteDatabase* db)
|
||||
: mDatabaseHandle(db->getDatabaseHandle()),
|
||||
mStatement(NULL),
|
||||
mDone(false)
|
||||
{
|
||||
}
|
||||
|
||||
SqliteStatement::~SqliteStatement() {
|
||||
finalize();
|
||||
}
|
||||
|
||||
bool SqliteStatement::prepare(const char* sql) {
|
||||
return (sqlite3_prepare_v2(mDatabaseHandle, sql, -1, &mStatement, NULL) == 0);
|
||||
}
|
||||
|
||||
bool SqliteStatement::step() {
|
||||
int ret = sqlite3_step(mStatement);
|
||||
if (ret == SQLITE_DONE) {
|
||||
mDone = true;
|
||||
return true;
|
||||
}
|
||||
return (ret == SQLITE_OK || ret == SQLITE_ROW);
|
||||
}
|
||||
|
||||
void SqliteStatement::reset() {
|
||||
sqlite3_reset(mStatement);
|
||||
mDone = false;
|
||||
}
|
||||
|
||||
void SqliteStatement::finalize() {
|
||||
if (mStatement) {
|
||||
sqlite3_finalize(mStatement);
|
||||
mStatement = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SqliteStatement::bind(int column, int value) {
|
||||
sqlite3_bind_int(mStatement, column, value);
|
||||
}
|
||||
|
||||
void SqliteStatement::bind(int column, const char* value) {
|
||||
sqlite3_bind_text(mStatement, column, value, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
int SqliteStatement::getColumnInt(int column) {
|
||||
return sqlite3_column_int(mStatement, column);
|
||||
}
|
||||
|
||||
int64_t SqliteStatement::getColumnInt64(int column) {
|
||||
return sqlite3_column_int64(mStatement, column);
|
||||
}
|
||||
|
||||
const char* SqliteStatement::getColumnString(int column) {
|
||||
return (const char *)sqlite3_column_text(mStatement, column);
|
||||
}
|
||||
51
media/mtp/SqliteStatement.h
Normal file
51
media/mtp/SqliteStatement.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _SQLITE_STATEMENT_H
|
||||
#define _SQLITE_STATEMENT_H
|
||||
|
||||
typedef struct sqlite3 sqlite3;
|
||||
typedef struct sqlite3_stmt sqlite3_stmt;
|
||||
class SqliteDatabase;
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class SqliteStatement {
|
||||
private:
|
||||
sqlite3* mDatabaseHandle;
|
||||
sqlite3_stmt* mStatement;
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
SqliteStatement(SqliteDatabase* db);
|
||||
virtual ~SqliteStatement();
|
||||
|
||||
bool prepare(const char* sql);
|
||||
bool step();
|
||||
void reset();
|
||||
void finalize();
|
||||
|
||||
void bind(int column, int value);
|
||||
void bind(int column, const char* value);
|
||||
|
||||
int getColumnInt(int column);
|
||||
int64_t getColumnInt64(int column);
|
||||
const char* getColumnString(int column);
|
||||
|
||||
inline bool isDone() const { return mDone; }
|
||||
};
|
||||
|
||||
#endif // _SQLITE_STATEMENT_H
|
||||
39
media/mtp/f_mtp.h
Normal file
39
media/mtp/f_mtp.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Gadget Function Driver for MTP
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Author: Mike Lockwood <lockwood@android.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_F_MTP_H
|
||||
#define __LINUX_USB_F_MTP_H
|
||||
|
||||
struct mtp_file_range {
|
||||
/* path for file to transfer */
|
||||
const char *path;
|
||||
/* strlen(path) */
|
||||
int path_length;
|
||||
/* offset in file for start of transfer */
|
||||
loff_t offset;
|
||||
/* number of bytes to transfer */
|
||||
size_t length;
|
||||
};
|
||||
|
||||
/* Sends the specified file range to the host */
|
||||
#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
|
||||
/* Receives data from the host and writes it to a file.
|
||||
* The file is created if it does not exist.
|
||||
*/
|
||||
#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
|
||||
|
||||
#endif /* __LINUX_USB_F_MTP_H */
|
||||
492
media/mtp/mtp.h
Normal file
492
media/mtp/mtp.h
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _MTP_H
|
||||
#define _MTP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint16_t MtpOperationCode;
|
||||
typedef uint16_t MtpResponseCode;
|
||||
typedef uint32_t MtpSessionID;
|
||||
typedef uint32_t MtpStorageID;
|
||||
typedef uint32_t MtpTransactionID;
|
||||
typedef uint16_t MtpObjectFormat;
|
||||
typedef uint16_t 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;
|
||||
|
||||
#define kInvalidObjectHandle 0xFFFFFFFF
|
||||
|
||||
#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
|
||||
|
||||
// Special values
|
||||
#define MTP_PARENT_ROOT 0xFFFFFFFF // parent is root of the storage
|
||||
|
||||
// MTP 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_REFERENCES 0x9810
|
||||
#define MTP_OPERATION_SET_OBJECT_REFERENCES 0x9811
|
||||
#define MTP_OPERATION_SKIP 0x9820
|
||||
|
||||
// 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 0x0000
|
||||
#define MTP_STORAGE_READ_ONLY_WITH_DELETE 0x0000
|
||||
|
||||
// Association Type
|
||||
#define MTP_ASSOCIATION_TYPE_UNDEFINED 0x0000
|
||||
#define MTP_ASSOCIATION_TYPE_GENERIC_FOLDER 0x0001
|
||||
|
||||
#endif // _MTP_H
|
||||
62
media/mtp/mtptest.cpp
Normal file
62
media/mtp/mtptest.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "mtp_usb"
|
||||
#include "cutils/log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "MtpServer.h"
|
||||
#include "MtpStorage.h"
|
||||
|
||||
|
||||
static void enable_usb_function(const char* name, bool enable) {
|
||||
char path[PATH_MAX];
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/class/usb_composite/%s/enable", name);
|
||||
int fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "could not open %s in enable_usb_function\n", path);
|
||||
exit(1);
|
||||
}
|
||||
write(fd, enable ? "1" : "0", 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// first disable UMS and enable MTP USB functions
|
||||
enable_usb_function("usb_mass_storage", false);
|
||||
enable_usb_function("mtp", true);
|
||||
|
||||
int fd = open("/dev/mtp_usb", O_RDWR);
|
||||
printf("open returned %d\n", fd);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "could not open MTP driver\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtpServer server(fd, "/data/data/mtp/mtp.db");
|
||||
server.addStorage("/sdcard");
|
||||
server.scanStorage();
|
||||
server.run();
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
134
media/mtp/ptptest.cpp
Normal file
134
media/mtp/ptptest.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <usbhost/usbhost.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
#include "MtpClient.h"
|
||||
|
||||
static struct usb_device *sCameraDevice = NULL;
|
||||
static int sCameraInterface = 0;
|
||||
static MtpClient *sClient = NULL;
|
||||
|
||||
|
||||
static void start_session(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
|
||||
struct usb_endpoint *ep_intr)
|
||||
{
|
||||
if (sClient)
|
||||
delete sClient;
|
||||
sClient = new MtpClient(ep_in, ep_out, ep_intr);
|
||||
sClient->openSession();
|
||||
sClient->getDeviceInfo();
|
||||
}
|
||||
|
||||
static void usb_device_added(const char *devname)
|
||||
{
|
||||
struct usb_descriptor_header* desc;
|
||||
struct usb_descriptor_iter iter;
|
||||
|
||||
struct usb_device *device = usb_device_open(devname);
|
||||
if (!device) return;
|
||||
|
||||
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)
|
||||
{
|
||||
printf("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
|
||||
usb_device_get_product_name(device));
|
||||
|
||||
// interface should be followed by three endpoints
|
||||
struct usb_endpoint_descriptor *ep, *ep_in_desc = NULL, *ep_out_desc = NULL, *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) {
|
||||
fprintf(stderr, "endpoints not found\n");
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
fprintf(stderr, "endpoints not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc);
|
||||
struct usb_endpoint *ep_out = usb_endpoint_open(device, ep_out_desc);
|
||||
struct usb_endpoint *ep_intr = usb_endpoint_open(device, ep_intr_desc);
|
||||
|
||||
if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
|
||||
fprintf(stderr, "usb_device_claim_interface failed\n");
|
||||
usb_endpoint_close(ep_in);
|
||||
usb_endpoint_close(ep_out);
|
||||
usb_endpoint_close(ep_intr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sCameraDevice) {
|
||||
usb_device_release_interface(sCameraDevice, sCameraInterface);
|
||||
usb_device_close(sCameraDevice);
|
||||
}
|
||||
sCameraDevice = device;
|
||||
start_session(ep_in, ep_out, ep_intr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device != sCameraDevice)
|
||||
usb_device_close(device);
|
||||
}
|
||||
|
||||
static void usb_device_removed(const char *devname)
|
||||
{
|
||||
if (sCameraDevice && !strcmp(devname, usb_device_get_name(sCameraDevice))) {
|
||||
delete sClient;
|
||||
printf("Camera removed!\n");
|
||||
usb_device_release_interface(sCameraDevice, sCameraInterface);
|
||||
usb_device_close(sCameraDevice);
|
||||
sCameraDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (usb_host_init(usb_device_added, usb_device_removed)) {
|
||||
fprintf(stderr, "usb_host_init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user