|
@@ -522,6 +522,15 @@ int list_and_issue_handles(
|
|
|
return count;
|
|
return count;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+struct GetObjectContext {
|
|
|
|
|
+ File* file;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+int GetObject_callback(void* ctx, uint8_t* buffer, int length) {
|
|
|
|
|
+ struct GetObjectContext* obj_ctx = (struct GetObjectContext*)ctx;
|
|
|
|
|
+ return storage_file_read(obj_ctx->file, buffer, length);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void GetObject(AppMTP* mtp, uint32_t transaction_id, uint32_t handle) {
|
|
void GetObject(AppMTP* mtp, uint32_t transaction_id, uint32_t handle) {
|
|
|
char* path = get_path_from_handle(mtp, handle);
|
|
char* path = get_path_from_handle(mtp, handle);
|
|
|
if(path == NULL) {
|
|
if(path == NULL) {
|
|
@@ -541,48 +550,19 @@ void GetObject(AppMTP* mtp, uint32_t transaction_id, uint32_t handle) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // I am a big dumbdumb
|
|
|
|
|
- bool is_first = true;
|
|
|
|
|
- uint8_t* buffer = malloc(sizeof(uint8_t) * MTP_MAX_PACKET_SIZE);
|
|
|
|
|
- size_t total_size = storage_file_size(file);
|
|
|
|
|
- size_t left_size = total_size;
|
|
|
|
|
-
|
|
|
|
|
- while(left_size > 0) {
|
|
|
|
|
- uint8_t* payload_ptr = buffer;
|
|
|
|
|
- size_t read_size = MTP_MAX_PACKET_SIZE;
|
|
|
|
|
- if(is_first) {
|
|
|
|
|
- FURI_LOG_I("MTP", "Sending MTP Header for GetObject req for file %s", path);
|
|
|
|
|
- read_size -= sizeof(struct MTPHeader);
|
|
|
|
|
- struct MTPHeader hdr = {
|
|
|
|
|
- .len = total_size + sizeof(struct MTPHeader),
|
|
|
|
|
- .type = MTP_TYPE_DATA,
|
|
|
|
|
- .op = MTP_OP_GET_OBJECT,
|
|
|
|
|
- .transaction_id = transaction_id,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- memcpy(buffer, &hdr, sizeof(struct MTPHeader));
|
|
|
|
|
- payload_ptr += sizeof(struct MTPHeader);
|
|
|
|
|
- read_size -= sizeof(struct MTPHeader);
|
|
|
|
|
- is_first = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- FURI_LOG_I("MTP", "Reading file %s", path);
|
|
|
|
|
- uint32_t read = storage_file_read(file, payload_ptr, read_size);
|
|
|
|
|
-
|
|
|
|
|
- size_t actual_packet_size = (payload_ptr - buffer) + // size of header (if exist),
|
|
|
|
|
- read;
|
|
|
|
|
|
|
+ uint32_t size = storage_file_size(file);
|
|
|
|
|
|
|
|
- FURI_LOG_I("MTP", "Read %ld bytes", read);
|
|
|
|
|
- usbd_ep_write(mtp->dev, MTP_EP_IN_ADDR, buffer, actual_packet_size);
|
|
|
|
|
|
|
+ struct GetObjectContext ctx = {
|
|
|
|
|
+ .file = file,
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- left_size -= read_size;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ send_mtp_response_stream(
|
|
|
|
|
+ mtp, MTP_TYPE_DATA, MTP_OP_GET_OBJECT, transaction_id, &ctx, GetObject_callback, size);
|
|
|
|
|
|
|
|
send_mtp_response(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL);
|
|
send_mtp_response(mtp, MTP_TYPE_RESPONSE, MTP_RESP_OK, transaction_id, NULL);
|
|
|
|
|
|
|
|
storage_file_close(file);
|
|
storage_file_close(file);
|
|
|
storage_file_free(file);
|
|
storage_file_free(file);
|
|
|
- free(buffer);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int GetObjectInfo(AppMTP* mtp, uint32_t handle, uint8_t* buffer) {
|
|
int GetObjectInfo(AppMTP* mtp, uint32_t handle, uint8_t* buffer) {
|
|
@@ -773,6 +753,46 @@ int GetDevicePropDesc(uint32_t prop_code, uint8_t* buffer) {
|
|
|
return ptr - buffer;
|
|
return ptr - buffer;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void send_mtp_response_stream(
|
|
|
|
|
+ AppMTP* mtp,
|
|
|
|
|
+ uint16_t resp_type,
|
|
|
|
|
+ uint16_t resp_code,
|
|
|
|
|
+ uint32_t transaction_id,
|
|
|
|
|
+ void* callback_context,
|
|
|
|
|
+ int (*callback)(void* ctx, uint8_t* buffer, int length),
|
|
|
|
|
+ uint32_t length) {
|
|
|
|
|
+ int chunk_idx = 0;
|
|
|
|
|
+
|
|
|
|
|
+ size_t buffer_available = MTP_MAX_PACKET_SIZE;
|
|
|
|
|
+ uint8_t* buffer = malloc(sizeof(uint8_t) * buffer_available);
|
|
|
|
|
+ uint8_t* ptr = buffer;
|
|
|
|
|
+
|
|
|
|
|
+ uint32_t sent_length = 0;
|
|
|
|
|
+
|
|
|
|
|
+ while(sent_length < length + sizeof(struct MTPHeader)) {
|
|
|
|
|
+ buffer_available = MTP_MAX_PACKET_SIZE;
|
|
|
|
|
+
|
|
|
|
|
+ if(chunk_idx == 0) {
|
|
|
|
|
+ struct MTPHeader* hdr = (struct MTPHeader*)buffer;
|
|
|
|
|
+ hdr->len = length;
|
|
|
|
|
+ hdr->type = resp_type;
|
|
|
|
|
+ hdr->op = resp_code;
|
|
|
|
|
+ hdr->transaction_id = transaction_id;
|
|
|
|
|
+
|
|
|
|
|
+ ptr += sizeof(*hdr);
|
|
|
|
|
+ buffer_available -= sizeof(*hdr);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int read_bytes = callback(callback_context, ptr, buffer_available);
|
|
|
|
|
+ uint32_t usb_bytes = (ptr - buffer) + read_bytes;
|
|
|
|
|
+ usbd_ep_write(mtp->dev, MTP_EP_IN_ADDR, buffer, usb_bytes);
|
|
|
|
|
+
|
|
|
|
|
+ sent_length += usb_bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ free(buffer);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void send_mtp_response_buffer(
|
|
void send_mtp_response_buffer(
|
|
|
AppMTP* mtp,
|
|
AppMTP* mtp,
|
|
|
uint16_t resp_type,
|
|
uint16_t resp_type,
|