Skip to content

Commit

Permalink
chore: stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex4386 committed Jun 16, 2024
1 parent 20bfacf commit afa8d78
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 3 deletions.
179 changes: 177 additions & 2 deletions src/scenes/mtp/mtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ uint16_t supported_operations[] = {
MTP_OP_GET_DEVICE_PROP_DESC,
MTP_OP_GET_DEVICE_PROP_VALUE,
MTP_OP_GET_OBJECT_PROPS_SUPPORTED,
MTP_OP_SET_OBJECT_PROP_VALUE};
MTP_OP_GET_OBJECT_PROP_DESC,
MTP_OP_GET_OBJECT_PROP_VALUE,
MTP_OP_SET_OBJECT_PROP_VALUE,
};

uint16_t supported_object_props[] = {
MTP_PROP_STORAGE_ID,
MTP_PROP_OBJECT_FORMAT,
MTP_PROP_OBJECT_FILE_NAME,
};
Expand Down Expand Up @@ -423,6 +425,175 @@ void handle_mtp_command(AppMTP* mtp, struct MTPContainer* container) {
mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, container->header.transaction_id, NULL, 0);
break;
}
case MTP_OP_GET_OBJECT_PROP_DESC: {
FURI_LOG_I("MTP", "GetObjectPropDesc operation");
uint8_t* buffer = malloc(sizeof(uint8_t) * 256);
uint32_t object_prop = container->params[0];
uint32_t object_format = container->params[1];
uint8_t* ptr = buffer;

struct MTPObjectPropDescHeaderChunk1* chunk1 =
(struct MTPObjectPropDescHeaderChunk1*)buffer;
chunk1->prop_code = object_prop;

if(object_prop == MTP_PROP_OBJECT_FORMAT) {
chunk1->data_type = MTP_TYPE_UINT16;
chunk1->get_set = MTP_PROP_GET;

uint8_t* data = buffer + sizeof(struct MTPObjectPropDescHeaderChunk1);
uint16_t* obj_format_ptr = (uint16_t*)data;
*obj_format_ptr = object_format;
obj_format_ptr++;

ptr = (uint8_t*)obj_format_ptr;
struct MTPObjectPropDescHeaderChunk2* chunk2 =
(struct MTPObjectPropDescHeaderChunk2*)ptr;

chunk2->group_code = 0;
chunk2->form_flag = 0x00;

ptr += sizeof(struct MTPObjectPropDescHeaderChunk2);
} else if(object_prop == MTP_PROP_OBJECT_FILE_NAME) {
chunk1->data_type = MTP_TYPE_STR;
chunk1->get_set = MTP_PROP_GETSET;

uint8_t* data = buffer + sizeof(struct MTPObjectPropDescHeaderChunk1);
uint8_t* ptr = (uint8_t*)data;

// fill factory default value
if(object_format == MTP_FORMAT_ASSOCIATION) {
// default filename is "New Folder"
uint16_t length = 0;
WriteMTPString(ptr, "New Folder", &length);

ptr += length;
} else {
// default filename is "New Folder"
uint16_t length = 0;
WriteMTPString(ptr, "", &length);

ptr += length;
}

struct MTPObjectPropDescHeaderChunk2* chunk2 =
(struct MTPObjectPropDescHeaderChunk2*)ptr;

chunk2->group_code = 0;
chunk2->form_flag = 0x00;

ptr += sizeof(struct MTPObjectPropDescHeaderChunk2);
} else {
send_mtp_response(
mtp, 3, MTP_RESP_INVALID_OBJECT_PROP_CODE, container->header.transaction_id, NULL);
free(buffer);
return;
}

int length = ptr - buffer;

send_mtp_response_buffer(
mtp,
MTP_TYPE_DATA,
MTP_OP_GET_OBJECT_PROP_DESC,
container->header.transaction_id,
buffer,
length);
free(buffer);
send_mtp_response_buffer(
mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, container->header.transaction_id, NULL, 0);
break;
}
case MTP_OP_GET_OBJECT_PROP_VALUE: {
FURI_LOG_I("MTP", "GetObjectPropValue operation");
uint8_t* buffer = malloc(sizeof(uint8_t) * 256);
uint32_t handle = container->params[0];
uint32_t object_prop = container->params[1];

char* path = get_path_from_handle(mtp, handle);
if(path == NULL) {
send_mtp_response(
mtp,
MTP_TYPE_RESPONSE,
MTP_RESP_INVALID_OBJECT_HANDLE,
container->header.transaction_id,
NULL);
free(buffer);
break;
}

FURI_LOG_I("MTP", "Getting object property (0x%04lx) for %s", object_prop, path);
if(object_prop == MTP_PROP_OBJECT_FORMAT) {
FileInfo fileinfo;
FS_Error err = storage_common_stat(mtp->storage, path, &fileinfo);
if(err != FSE_OK) {
send_mtp_response(
mtp,
MTP_TYPE_RESPONSE,
MTP_RESP_INVALID_OBJECT_HANDLE,
container->header.transaction_id,
NULL);
free(buffer);
break;
}

bool is_dir = file_info_is_dir(&fileinfo);
uint16_t format = is_dir ? MTP_FORMAT_ASSOCIATION : MTP_FORMAT_UNDEFINED;

memcpy(buffer, &format, sizeof(uint16_t));
send_mtp_response_buffer(
mtp,
MTP_TYPE_DATA,
MTP_OP_GET_OBJECT_PROP_VALUE,
container->header.transaction_id,
buffer,
sizeof(uint16_t));
} else if(object_prop == MTP_PROP_OBJECT_FILE_NAME) {
char* path = get_path_from_handle(mtp, handle);
if(path == NULL) {
send_mtp_response(
mtp,
MTP_TYPE_RESPONSE,
MTP_RESP_INVALID_OBJECT_HANDLE,
container->header.transaction_id,
NULL);
free(buffer);
break;
}

uint8_t* ptr = buffer;
char* file_name = strrchr(path, '/');
uint16_t length = 0;

WriteMTPString(ptr, file_name + 1, &length);

print_bytes("MTP FileName", ptr, length);
send_mtp_response_buffer(
mtp,
MTP_TYPE_DATA,
MTP_OP_GET_OBJECT_PROP_VALUE,
container->header.transaction_id,
buffer,
length);
} else {
send_mtp_response(
mtp,
MTP_TYPE_RESPONSE,
MTP_RESP_INVALID_OBJECT_PROP_CODE,
container->header.transaction_id,
NULL);
break;
}

free(buffer);
send_mtp_response(
mtp,
MTP_TYPE_RESPONSE,
MTP_OP_GET_OBJECT_PROP_VALUE,
container->header.transaction_id,
NULL);

break;
}
case MTP_OP_DELETE_OBJECT:
FURI_LOG_I("MTP", "DeleteObject operation");
if(DeleteObject(mtp, container->params[0])) {
Expand Down Expand Up @@ -955,6 +1126,10 @@ void send_mtp_response_buffer(
ctx->size = size;
ctx->sent = 0;

if(resp_type == MTP_TYPE_DATA) {
print_bytes("MTP Data", buffer, size);
}

send_mtp_response_stream(
mtp, resp_type, resp_code, transaction_id, ctx, send_mtp_response_buffer_callback, size);
free(ctx);
Expand Down
41 changes: 40 additions & 1 deletion src/scenes/mtp/mtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,36 @@
#define MTP_OP_SET_OBJECT_PROP_VALUE 0x9804

// MTP Object Props
#define MTP_PROP_STORAGE_ID 0xDC01
#define MTP_PROP_OBJECT_FORMAT 0xDC02
#define MTP_PROP_OBJECT_FILE_NAME 0xDC07

// MTP DataTypes
#define MTP_TYPE_INT8 0x0001
#define MTP_TYPE_UINT8 0x0002
#define MTP_TYPE_INT16 0x0003
#define MTP_TYPE_UINT16 0x0004
#define MTP_TYPE_INT32 0x0005
#define MTP_TYPE_UINT32 0x0006
#define MTP_TYPE_INT64 0x0007
#define MTP_TYPE_UINT64 0x0008
#define MTP_TYPE_INT128 0x0009
#define MTP_TYPE_UINT128 0x000A
#define MTP_TYPE_AINT8 0x4001
#define MTP_TYPE_AUINT8 0x4002
#define MTP_TYPE_AINT16 0x4003
#define MTP_TYPE_AUINT16 0x4004
#define MTP_TYPE_AINT32 0x4005
#define MTP_TYPE_AUINT32 0x4006
#define MTP_TYPE_AINT64 0x4007
#define MTP_TYPE_AUINT64 0x4008
#define MTP_TYPE_AINT128 0x4009
#define MTP_TYPE_AUINT128 0x400A
#define MTP_TYPE_STR 0xFFFF

// MTP Prop Get/Set
#define MTP_PROP_GET 0x00
#define MTP_PROP_GETSET 0x01

// MTP Response Codes
#define MTP_RESP_UNKNOWN 0x2000
#define MTP_RESP_OK 0x2001
Expand Down Expand Up @@ -68,6 +94,8 @@
#define MTP_RESP_CAPTURE_ALREADY_TERMINATED 0x2018
#define MTP_RESP_DEVICE_BUSY 0x2019

#define MTP_RESP_INVALID_OBJECT_PROP_CODE 0xA801

// Storage IDs
#define INTERNAL_STORAGE_ID 0x00010001
#define EXTERNAL_STORAGE_ID 0x00020001
Expand Down Expand Up @@ -202,3 +230,14 @@ struct MTPResponseBufferContext {
uint32_t size;
uint32_t sent;
};

struct MTPObjectPropDescHeaderChunk1 {
uint16_t prop_code;
uint16_t data_type;
uint8_t get_set; // 0x00: Get, 0x01: GetSet
};

struct MTPObjectPropDescHeaderChunk2 {
uint32_t group_code;
uint8_t form_flag;
};

0 comments on commit afa8d78

Please sign in to comment.