diff options
author | Mike Lockwood <lockwood@android.com> | 2010-07-26 20:44:42 -0400 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2010-07-26 20:47:35 -0400 |
commit | 5fd1ff0aa370958dfdbabb6026c1d383d17df97f (patch) | |
tree | 8458539ce6e0d8a1aa078e93568a5b0d0c034ed8 /media/tests/mtp | |
parent | ad0643a330db13c8f11b1a71fbb7262570114f4d (diff) | |
download | frameworks_base-5fd1ff0aa370958dfdbabb6026c1d383d17df97f.zip frameworks_base-5fd1ff0aa370958dfdbabb6026c1d383d17df97f.tar.gz frameworks_base-5fd1ff0aa370958dfdbabb6026c1d383d17df97f.tar.bz2 |
Simple command line test tool for MTP host.
Change-Id: Ifd13e1ca5d49a5477a9850d94d443a50bbc32ff1
Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'media/tests/mtp')
-rw-r--r-- | media/tests/mtp/Android.mk | 57 | ||||
-rw-r--r-- | media/tests/mtp/MtpFile.cpp | 187 | ||||
-rw-r--r-- | media/tests/mtp/MtpFile.h | 57 | ||||
-rw-r--r-- | media/tests/mtp/mtp.cpp | 370 |
4 files changed, 671 insertions, 0 deletions
diff --git a/media/tests/mtp/Android.mk b/media/tests/mtp/Android.mk new file mode 100644 index 0000000..8cdfb69 --- /dev/null +++ b/media/tests/mtp/Android.mk @@ -0,0 +1,57 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + mtp.cpp \ + MtpFile.cpp \ + +LOCAL_C_INCLUDES += \ + frameworks/base/media/mtp \ + +LOCAL_CFLAGS := -DMTP_HOST + +LOCAL_MODULE := mtp + +LOCAL_STATIC_LIBRARIES := libmtp libusbhost libutils libcutils + +include $(BUILD_EXECUTABLE) + +ifeq ($(HOST_OS),linux) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + mtp.cpp \ + MtpFile.cpp \ + ../../../libs/utils/RefBase.cpp \ + ../../../libs/utils/SharedBuffer.cpp \ + ../../../libs/utils/Threads.cpp \ + ../../../libs/utils/VectorImpl.cpp \ + +LOCAL_C_INCLUDES += \ + frameworks/base/media/mtp \ + +LOCAL_CFLAGS := -DMTP_HOST -g -O0 + +have_readline := $(wildcard /usr/include/readline/readline.h) +have_history := $(wildcard /usr/lib/libhistory*) +ifneq ($(strip $(have_readline)),) +LOCAL_CFLAGS += -DHAVE_READLINE=1 +endif + +LOCAL_LDLIBS += -lpthread +ifneq ($(strip $(have_readline)),) +LOCAL_LDLIBS += -lreadline -lncurses +endif +ifneq ($(strip $(have_history)),) +LOCAL_LDLIBS += -lhistory +endif + +LOCAL_MODULE := mtp + +LOCAL_STATIC_LIBRARIES := libmtp libusbhost libcutils + +include $(BUILD_HOST_EXECUTABLE) + +endif diff --git a/media/tests/mtp/MtpFile.cpp b/media/tests/mtp/MtpFile.cpp new file mode 100644 index 0000000..00d328e --- /dev/null +++ b/media/tests/mtp/MtpFile.cpp @@ -0,0 +1,187 @@ +/* + * 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 "MtpClient.h" +#include "MtpDevice.h" +#include "MtpDeviceInfo.h" +#include "MtpObjectInfo.h" +#include "MtpStorage.h" +#include "MtpUtils.h" + +#include "MtpFile.h" + +namespace android { + +MtpClient* MtpFile::sClient = NULL; + +MtpFile::MtpFile(MtpDevice* device) + : mDevice(device), + mStorage(0), + mHandle(0) +{ +} + +MtpFile::MtpFile(MtpDevice* device, MtpStorageID storage) + : mDevice(device), + mStorage(storage), + mHandle(0) +{ +} + +MtpFile::MtpFile(MtpDevice* device, MtpStorageID storage, MtpObjectHandle handle) + : mDevice(device), + mStorage(storage), + mHandle(handle) +{ +} + +MtpFile::MtpFile(MtpFile* file) + : mDevice(file->mDevice), + mStorage(file->mStorage), + mHandle(file->mHandle) +{ +} + +MtpFile::~MtpFile() { +} + +void MtpFile::print() { + if (mHandle) { + + } else if (mStorage) { + printf("%x\n", mStorage); + } else { + int id = mDevice->getID(); + MtpDeviceInfo* info = mDevice->getDeviceInfo(); + if (info) + printf("%d\t%s %s %s\n", id, info->mManufacturer, info->mModel, info->mSerial); + else + printf("%d\t(no device info available)\n", id); + delete info; + } +} + +MtpObjectInfo* MtpFile::getObjectInfo() { + return mDevice->getObjectInfo(mHandle); +} + +void MtpFile::list() { + if (mStorage) { + MtpObjectHandleList* handles = mDevice->getObjectHandles(mStorage, 0, + (mHandle ? mHandle : -1)); + if (handles) { + for (int i = 0; i < handles->size(); i++) { + MtpObjectHandle handle = (*handles)[i]; + MtpObjectInfo* info = mDevice->getObjectInfo(handle); + if (info) { + char modified[100]; + struct tm tm; + + gmtime_r(&info->mDateModified, &tm); + strftime(modified, sizeof(modified), "%a %b %e %H:%M:%S GMT %Y", &tm); + printf("%s Handle: %d Format: %04X Size: %d Modified: %s\n", + info->mName, handle, info->mFormat, info->mCompressedSize, modified); + delete info; + } + } + delete handles; + } + } else { + // list storage units for device + MtpStorageIDList* storageList = mDevice->getStorageIDs(); + for (int i = 0; i < storageList->size(); i++) { + MtpStorageID storageID = (*storageList)[i]; + printf("%x\n", storageID); + } + } +} + +void MtpFile::init(MtpClient* client) { + sClient = client; +} + +MtpFile* MtpFile::parsePath(MtpFile* base, char* path) { + MtpDevice* device = NULL; + MtpStorageID storage = 0; + MtpObjectHandle handle = 0; + + if (path[0] != '/' && base) { + device = base->mDevice; + storage = base->mStorage; + handle = base->mHandle; + } + + // parse an absolute path + if (path[0] == '/') + path++; + char* tok = strtok(path, "/"); + while (tok) { + if (storage) { + // find child of current handle + MtpObjectHandleList* handles = device->getObjectHandles(storage, 0, + (handle ? handle : -1)); + MtpObjectHandle childHandle = 0; + + if (handles) { + for (int i = 0; i < handles->size() && !childHandle; i++) { + MtpObjectHandle handle = (*handles)[i]; + MtpObjectInfo* info = device->getObjectInfo(handle); + if (info && !strcmp(tok, info->mName)) + childHandle = handle; + delete info; + } + delete handles; + } + if (childHandle) + handle = childHandle; + else + return NULL; + } else if (device) { + unsigned int id; + // find storage for the device + if (sscanf(tok, "%x", &id) == 1) { + MtpStorageIDList* storageList = device->getStorageIDs(); + bool found = false; + for (int i = 0; i < storageList->size(); i++) { + if ((*storageList)[i] == id) { + found = true; + break; + } + } + if (found) + storage = id; + else + return NULL; + } + } else { + // find device + unsigned int id; + if (sscanf(tok, "%d", &id) == 1) + device = sClient->getDevice(id); + if (!device) + return NULL; + } + + tok = strtok(NULL, "/"); + } + + if (device) + return new MtpFile(device, storage, handle); + else + return NULL; +} + +} diff --git a/media/tests/mtp/MtpFile.h b/media/tests/mtp/MtpFile.h new file mode 100644 index 0000000..ab8762b --- /dev/null +++ b/media/tests/mtp/MtpFile.h @@ -0,0 +1,57 @@ +/* + * 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_FILE_H +#define _MTP_FILE_H + +#include "MtpTypes.h" + +namespace android { + +class MtpClient; +class MtpDevice; +class MtpObjectInfo; + +// File-like abstraction for the interactive shell. +// This can be used to represent an MTP device, storage unit or object +// (either file or association). +class MtpFile { +private: + MtpDevice* mDevice; + MtpStorageID mStorage; + MtpObjectHandle mHandle; + static MtpClient* sClient; + +public: + MtpFile(MtpDevice* device); + MtpFile(MtpDevice* device, MtpStorageID storage); + MtpFile(MtpDevice* device, MtpStorageID storage, MtpObjectHandle handle); + MtpFile(MtpFile* file); + virtual ~MtpFile(); + + MtpObjectInfo* getObjectInfo(); + void print(); + void list(); + + inline MtpDevice* getDevice() const { return mDevice; } + + static void init(MtpClient* client); + static MtpFile* parsePath(MtpFile* base, char* path); +}; + +} + +#endif // _MTP_DIRECTORY_H diff --git a/media/tests/mtp/mtp.cpp b/media/tests/mtp/mtp.cpp new file mode 100644 index 0000000..2c5e23b --- /dev/null +++ b/media/tests/mtp/mtp.cpp @@ -0,0 +1,370 @@ +/* + * 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 <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#if HAVE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif + +#include "MtpClient.h" +#include "MtpDevice.h" +#include "MtpObjectInfo.h" + +#include "MtpFile.h" + +#define PROMPT "mtp> " + +using namespace android; + +static MtpClient* sClient = NULL; + +// current working directory information for interactive shell +static MtpFile* sCurrentDirectory = NULL; + +static MtpFile* parse_path(char* path) { + return MtpFile::parsePath(sCurrentDirectory, path); +} + +class MyClient : public MtpClient { +private: + virtual void deviceAdded(MtpDevice *device) { + } + + virtual void deviceRemoved(MtpDevice *device) { + } + +public: +}; + +static void init() { + sClient = new MyClient; + sClient->start(); + MtpFile::init(sClient); +} + +static int set_cwd(int argc, char* argv[]) { + if (argc != 1) { + fprintf(stderr, "cd should have one argument\n"); + return -1; + } + if (!strcmp(argv[0], "/")) { + delete sCurrentDirectory; + sCurrentDirectory = NULL; + } + else { + MtpFile* file = parse_path(argv[0]); + if (file) { + delete sCurrentDirectory; + sCurrentDirectory = file; + } else { + fprintf(stderr, "could not find %s\n", argv[0]); + return -1; + } + } + return 0; +} + +static void list_devices() { + // TODO - need to make sure the list will not change while iterating + MtpDeviceList& devices = sClient->getDeviceList(); + for (int i = 0; i < devices.size(); i++) { + MtpDevice* device = devices[i]; + MtpFile* file = new MtpFile(device); + file->print(); + delete file; + } +} + +static int list(int argc, char* argv[]) { + if (argc == 0) { + // list cwd + if (sCurrentDirectory) { + sCurrentDirectory->list(); + } else { + list_devices(); + } + } + + for (int i = 0; i < argc; i++) { + char* path = argv[i]; + if (!strcmp(path, "/")) { + list_devices(); + } else { + MtpFile* file = parse_path(path); + if (!file) { + fprintf(stderr, "could not find %s\n", path); + return -1; + } + file->list(); + } + } + + return 0; +} + +static int get_file(int argc, char* argv[]) { + int ret = -1; + int srcFD = -1; + int destFD = -1; + MtpFile* srcFile = NULL; + MtpObjectInfo* info = NULL; + char* dest; + + if (argc < 1) { + fprintf(stderr, "not enough arguments\n"); + return -1; + } else if (argc > 2) { + fprintf(stderr, "too many arguments\n"); + return -1; + } + + // find source object + char* src = argv[0]; + srcFile = parse_path(src); + if (!srcFile) { + fprintf(stderr, "could not find %s\n", src); + return -1; + } + info = srcFile->getObjectInfo(); + if (!info) { + fprintf(stderr, "could not find object info for %s\n", src); + goto fail; + } + if (info->mFormat == MTP_FORMAT_ASSOCIATION) { + fprintf(stderr, "copying directories not implemented yet\n"); + goto fail; + } + + dest = (argc > 1 ? argv[1] : info->mName); + destFD = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (destFD < 0) { + fprintf(stderr, "could not create %s\n", dest); + goto fail; + } + srcFD = srcFile->getDevice()->readObject(info->mHandle, info->mCompressedSize); + if (srcFD < 0) + goto fail; + + char buffer[65536]; + while (1) { + int count = read(srcFD, buffer, sizeof(buffer)); + if (count <= 0) + break; + write(destFD, buffer, count); + } + // FIXME - error checking and reporting + ret = 0; + +fail: + delete srcFile; + delete info; + if (srcFD >= 0) + close(srcFD); + if (destFD >= 0) + close(destFD); + return ret; +} + +static int put_file(int argc, char* argv[]) { + int ret = -1; + int srcFD = -1; + MtpFile* destFile = NULL; + MtpObjectInfo* srcInfo = NULL; + MtpObjectInfo* destInfo = NULL; + MtpObjectHandle handle; + struct stat statbuf; + const char* lastSlash; + + if (argc < 1) { + fprintf(stderr, "not enough arguments\n"); + return -1; + } else if (argc > 2) { + fprintf(stderr, "too many arguments\n"); + return -1; + } + const char* src = argv[0]; + srcFD = open(src, O_RDONLY); + if (srcFD < 0) { + fprintf(stderr, "could not open %s\n", src); + goto fail; + } + if (argc == 2) { + char* dest = argv[1]; + destFile = parse_path(dest); + if (!destFile) { + fprintf(stderr, "could not find %s\n", dest); + goto fail; + } + } else { + if (!sCurrentDirectory) { + fprintf(stderr, "current working directory not set\n"); + goto fail; + } + destFile = new MtpFile(sCurrentDirectory); + } + + destInfo = destFile->getObjectInfo(); + if (!destInfo) { + fprintf(stderr, "could not find object info destination directory\n"); + goto fail; + } + if (destInfo->mFormat != MTP_FORMAT_ASSOCIATION) { + fprintf(stderr, "destination not a directory\n"); + goto fail; + } + + if (fstat(srcFD, &statbuf)) + goto fail; + + srcInfo = new MtpObjectInfo(0); + srcInfo->mStorageID = destInfo->mStorageID; + srcInfo->mFormat = MTP_FORMAT_EXIF_JPEG; // FIXME + srcInfo->mCompressedSize = statbuf.st_size; + srcInfo->mParent = destInfo->mHandle; + lastSlash = strrchr(src, '/'); + srcInfo->mName = strdup(lastSlash ? lastSlash + 1 : src); + srcInfo->mDateModified = statbuf.st_mtime; + handle = destFile->getDevice()->sendObjectInfo(srcInfo); + if (handle <= 0) { + printf("sendObjectInfo returned %04X\n", handle); + goto fail; + } + if (destFile->getDevice()->sendObject(srcInfo, srcFD)) + ret = 0; + +fail: + delete destFile; + delete srcInfo; + delete destInfo; + if (srcFD >= 0) + close(srcFD); + printf("returning %d\n", ret); + return ret; +} + +typedef int (* command_func)(int argc, char* argv[]); + +struct command_table_entry { + const char* name; + command_func func; +}; + +const command_table_entry command_list[] = { + { "cd", set_cwd }, + { "ls", list }, + { "get", get_file }, + { "put", put_file }, + { NULL, NULL }, +}; + + +static int do_command(int argc, char* argv[]) { + const command_table_entry* command = command_list; + const char* name = *argv++; + argc--; + + while (command->name) { + if (!strcmp(command->name, name)) + return command->func(argc, argv); + else + command++; + } + fprintf(stderr, "unknown command %s\n", name); + return -1; +} + +static int shell() { + int argc; + int result = 0; +#define MAX_ARGS 100 + char* argv[MAX_ARGS]; + +#if HAVE_READLINE + using_history(); +#endif + + while (1) { +#if HAVE_READLINE + char* line = readline(PROMPT); + if (!line) { + printf("\n"); + exit(0); + } +#else + char buffer[1000]; + printf("%s", PROMPT); + char* line = NULL; + size_t length = 0; + + buffer[0] = 0; + fgets(buffer, sizeof(buffer), stdin); + int count = strlen(buffer); + if (count > 0 && buffer[0] == EOF) { + printf("\n"); + exit(0); + } + if (count > 0 && line[count - 1] == '\n') + line[count - 1] == 0; +#endif + char* tok = strtok(line, " \t\n\r"); + if (!tok) + continue; + if (!strcmp(tok, "quit") || !strcmp(tok, "exit")) { + exit(0); + } +#if HAVE_READLINE + add_history(line); +#endif + argc = 0; + while (tok) { + if (argc + 1 == MAX_ARGS) { + fprintf(stderr, "too many arguments\n"); + result = -1; + goto bottom_of_loop; + } + + argv[argc++] = strdup(tok); + tok = strtok(NULL, " \t\n\r"); + } + + result = do_command(argc, argv); + +bottom_of_loop: + for (int i = 0; i < argc; i++) + free(argv[i]); + free(line); + } + + return result; +} + +int main(int argc, char* argv[]) { + init(); + + if (argc == 1) + return shell(); + else + return do_command(argc - 1, argv + 1); +} |