From d21ebde022384442e1bd872a5515d98e18648382 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Mar 2024 23:58:53 -0500 Subject: [PATCH] New, more optimizable writing routines Old (void **) funcs were a bad idea. --- src/camlib.h | 16 ++++--- src/canon_adv.c | 32 +++++++------- src/cl_data.h | 2 +- src/data.c | 106 ++++++++++++++++++++--------------------------- src/operations.c | 3 +- src/packet.c | 50 +++++++++++++++++++--- test/test.c | 15 +++++++ 7 files changed, 134 insertions(+), 90 deletions(-) diff --git a/src/camlib.h b/src/camlib.h index b6d5dbc..fe4c973 100644 --- a/src/camlib.h +++ b/src/camlib.h @@ -122,7 +122,8 @@ struct PtpRuntime { /// is 512, but certain comm backends can manage more. For TCP, this isn't used. int max_packet_size; - /// @brief Info about current connection, used to detect the vendor, supported opodes. + /// @brief Info about current connection, used to detect camera type, supported opodes, etc + /// @note Set by ptp_parse_device_info. struct PtpDeviceInfo *di; int device_type; @@ -249,18 +250,21 @@ int ptp_buffer_resize(struct PtpRuntime *r, size_t size); uint8_t ptp_read_uint8(void *dat); uint16_t ptp_read_uint16(void *dat); uint32_t ptp_read_uint32(void *dat); -void ptp_read_string(void *dat, char *string, int max); -int ptp_read_uint16_array(void *dat, uint16_t *buf, int max); -int ptp_read_uint32_array(void *dat, uint16_t *buf, int max); -int ptp_wide_string(char *buffer, int max, char *input); void ptp_write_uint8(void *dat, uint8_t b); int ptp_write_uint32(void *dat, uint32_t b); + +void ptp_read_string(void *dat, char *string, int max); +int ptp_read_uint16_array(void *dat, uint16_t *buf, int max); int ptp_write_string(void *dat, char *string); -int ptp_write_utf8_string(void *dat, char *string); int ptp_write_unicode_string(char *dat, char *string); int ptp_read_unicode_string(char *buffer, char *dat, int max); void ptp_read_utf8_string(void *dat, char *string, int max); +int ptp_read_string2(uint8_t *dat, char *string, int max); +int ptp_write_string2(uint8_t *dat, char *string); +int ptp_write_utf8_string(void *dat, char *string); +int ptp_read_uint16_array2(uint8_t *dat, uint16_t *buf, int max, int *length); + inline static int ptp_write_u8 (void *buf, uint8_t out) { ((uint8_t *)buf)[0] = out; return 1; } inline static int ptp_write_u16(void *buf, uint16_t out) { ((uint16_t *)buf)[0] = out; return 2; } inline static int ptp_write_u32(void *buf, uint32_t out) { ((uint32_t *)buf)[0] = out; return 4; } diff --git a/src/canon_adv.c b/src/canon_adv.c index 09e0102..8dedbbb 100644 --- a/src/canon_adv.c +++ b/src/canon_adv.c @@ -183,20 +183,18 @@ static struct Tokens *lex_evproc_command(char string[]) { return toks; } -char *canon_evproc_pack(int *length, char *string) { +char *canon_evproc_pack(int *out_length, char *string) { + int length = 0; // Allocate some memory for the footer, we will use this later void *footer = malloc(500); - void *footer_ptr = footer; uint32_t *long_args = footer; int footer_length = 0; // Set long_args to zero - footer_length += ptp_write_uint32(&footer_ptr, 0); + footer_length += ptp_write_u32(footer + footer_length, 0); struct Tokens *toks = lex_evproc_command(string); - // You will need to make sure your request never exceeds this - // I can't be bothered to add bound checks char *data = malloc(500); if (toks->length == 0) { @@ -209,16 +207,16 @@ char *canon_evproc_pack(int *length, char *string) { int len = strlen(toks->t[0].string); memcpy(data, toks->t[0].string, len); data[len] = '\0'; - (*length) += len + 1; + length += len + 1; } else { ptp_verbose_log("Error, first parameter must be plain text.\n"); return NULL; } // First uint32 is the number of parameters, we will save this ptr and modify it as we parse - uint32_t *num_args = (uint32_t *)(data + (*length)); + uint32_t *num_args = (uint32_t *)(data + length); (*num_args) = 0; - (*length) += 4; + length += 4; // Pack parameters into data for (int t = 1; t < toks->length; t++) { @@ -229,8 +227,8 @@ char *canon_evproc_pack(int *length, char *string) { integer.type = EOS_TOK_INT; integer.number = toks->t[t].integer; - memcpy(data + (*length), &integer, sizeof(struct EvProcParam)); - (*length) += sizeof(struct EvProcParam); + memcpy(data + length, &integer, sizeof(struct EvProcParam)); + length += sizeof(struct EvProcParam); (*num_args)++; } break; @@ -241,12 +239,12 @@ char *canon_evproc_pack(int *length, char *string) { pstring.type = EOS_TOK_STR; pstring.size = strlen(toks->t[t].string) + 1; - memcpy(data + (*length), &pstring, sizeof(struct EvProcParam)); + memcpy(data + length, &pstring, sizeof(struct EvProcParam)); - (*length) += sizeof(struct EvProcParam); + length += sizeof(struct EvProcParam); - footer_length += ptp_write_uint32((void **)&footer_ptr, 0); - footer_length += ptp_write_utf8_string((void **)&footer_ptr, toks->t[t].string); + footer_length += ptp_write_u32(footer + footer_length, 0); + footer_length += ptp_write_utf8_string(footer + footer_length, toks->t[t].string); (*long_args)++; (*num_args)++; @@ -255,10 +253,12 @@ char *canon_evproc_pack(int *length, char *string) { } if (footer_length) { - memcpy(data + (*length), footer, footer_length); - (*length) += footer_length; + memcpy(data + length, footer, footer_length); + length += footer_length; } + (*out_length) = length; + free(footer); free(toks); diff --git a/src/cl_data.h b/src/cl_data.h index 05ec083..73e9cde 100644 --- a/src/cl_data.h +++ b/src/cl_data.h @@ -197,7 +197,7 @@ struct PtpFujiObjectInfo { #pragma pack(pop) #ifdef CAMLIB_INCLUDE_IMPL -int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void **d, int max); +int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void *buf, int max); int ptp_parse_prop_value(struct PtpRuntime *r); int ptp_parse_device_info(struct PtpRuntime *r, struct PtpDeviceInfo *di); diff --git a/src/data.c b/src/data.c index 59e9a01..82c6096 100644 --- a/src/data.c +++ b/src/data.c @@ -24,17 +24,6 @@ static int osnprintf(char *str, int cur, int size, const char *format, ...) { return r; } -// We do not have proper UTF16 support for now -static void format_sane_string(char *string) { - for (int i = 0; string[i] != '\0'; i++) { - if (string[i] < 0) { - string[i] = '?'; - } else if (string[i] < 32) { - string[i] = ' '; - } - } -} - int ptp_get_data_size(void *d, int type) { switch (type) { case PTP_TC_INT8: @@ -61,31 +50,35 @@ int ptp_get_data_size(void *d, int type) { return 0; } -int ptp_parse_data(void *d, int type) { +int ptp_parse_data(void *d, int type, int *out) { + uint8_t a; + uint16_t b; + uint32_t c; switch (type) { case PTP_TC_INT8: case PTP_TC_UINT8: - return (uint8_t)ptp_read_uint8(d); + ptp_read_u8(d, &a); (*out) = (int)a; return 1; case PTP_TC_INT16: case PTP_TC_UINT16: - return (uint16_t)ptp_read_uint16(d); + ptp_read_u16(d, &b); (*out) = (int)b; return 2; case PTP_TC_INT32: case PTP_TC_UINT32: - return (uint32_t)ptp_read_uint32(d); + ptp_read_u16(d, &b); (*out) = (int)b; return 4; } - return ptp_get_data_size(*((void **)d), type); + // skip the array + return ptp_get_data_size(d, type); } int ptp_parse_prop_value(struct PtpRuntime *r) { - void *d = ptp_get_payload(r); + uint8_t *d = ptp_get_payload(r); switch (ptp_get_payload_length(r)) { case 1: - return (int)(((uint8_t *)d)[0]); + return (int)(d[0]); case 2: - return (int)(((uint16_t *)d)[0]); + return (int)(d[0]); case 4: - return (int)(((uint32_t *)d)[0]); + return (int)(d[0]); } return -1; @@ -95,8 +88,8 @@ int ptp_parse_prop_desc(struct PtpRuntime *r, struct PtpDevPropDesc *oi) { uint8_t *d = ptp_get_payload(r); memcpy(oi, d, PTP_PROP_DESC_VAR_START); d += PTP_PROP_DESC_VAR_START; - oi->default_value = ptp_parse_data(&d, oi->data_type); - oi->current_value = ptp_parse_data(&d, oi->data_type); + d += ptp_parse_data(d, oi->data_type, &oi->default_value); + d += ptp_parse_data(d, oi->data_type, &oi->current_value); // TODO: Form flag + form (for properties like date/time) return 0; @@ -106,38 +99,36 @@ int ptp_parse_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi) { uint8_t *d = ptp_get_payload(r); memcpy(oi, d, PTP_OBJ_INFO_VAR_START); d += PTP_OBJ_INFO_VAR_START; - ptp_read_string(&d, oi->filename, sizeof(oi->filename)); - ptp_read_string(&d, oi->date_created, sizeof(oi->date_created)); - ptp_read_string(&d, oi->date_modified, sizeof(oi->date_modified)); - ptp_read_string(&d, oi->keywords, sizeof(oi->keywords)); + d += ptp_read_string2(d, oi->filename, sizeof(oi->filename)); + d += ptp_read_string2(d, oi->date_created, sizeof(oi->date_created)); + d += ptp_read_string2(d, oi->date_modified, sizeof(oi->date_modified)); + d += ptp_read_string2(d, oi->keywords, sizeof(oi->keywords)); return 0; } // TODO: Different API -int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void **dat, int max) { +int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void *buf, int max) { if (1024 > max) { return 0; } - uint8_t **ptr = (uint8_t **)(dat); - memcpy(*ptr, oi, PTP_OBJ_INFO_VAR_START); - (*ptr) += PTP_OBJ_INFO_VAR_START; - - int length = PTP_OBJ_INFO_VAR_START; + memcpy(buf, oi, PTP_OBJ_INFO_VAR_START); + buf += PTP_OBJ_INFO_VAR_START; // If the string is empty, don't add it to the packet + int of = PTP_OBJ_INFO_VAR_START; if (oi->filename[0] != '\0') - length += ptp_write_string((ptr), oi->filename); + of += ptp_write_string2(buf + of, oi->filename); if (oi->date_created[0] != '\0') - length += ptp_write_string((ptr), oi->date_created); + of += ptp_write_string2(buf + of, oi->date_created); if (oi->date_modified[0] != '\0') - length += ptp_write_string((ptr), oi->date_modified); + of += ptp_write_string2(buf + of, oi->date_modified); if (oi->keywords[0] != '\0') - length += ptp_write_string((ptr), oi->keywords); + of += ptp_write_string2(buf + of, oi->keywords); // Return pointer length added - return length; + return of; } void *ptp_pack_chdk_upload_file(struct PtpRuntime *r, char *in, char *out, int *length) { @@ -166,34 +157,29 @@ void *ptp_pack_chdk_upload_file(struct PtpRuntime *r, char *in, char *out, int * } int ptp_parse_device_info(struct PtpRuntime *r, struct PtpDeviceInfo *di) { - void *e = ptp_get_payload(r); - - di->standard_version = ptp_read_uint16(&e); - di->vendor_ext_id = ptp_read_uint32(&e); - di->version = ptp_read_uint16(&e); - - ptp_read_string(&e, di->extensions, sizeof(di->extensions)); + uint8_t *e = ptp_get_payload(r); - di->functional_mode = ptp_read_uint16(&e); + e += ptp_read_u16(e, &di->standard_version); + e += ptp_read_u32(e, &di->vendor_ext_id); + e += ptp_read_u16(e, &di->version); - di->ops_supported_length = ptp_read_uint16_array(&e, di->ops_supported, sizeof(di->ops_supported) / 2); - di->events_supported_length = ptp_read_uint16_array(&e, di->events_supported, sizeof(di->events_supported) / 2); - di->props_supported_length = ptp_read_uint16_array(&e, di->props_supported, sizeof(di->props_supported) / 2); - di->capture_formats_length = ptp_read_uint16_array(&e, di->capture_formats, sizeof(di->capture_formats) / 2); - di->playback_formats_length = ptp_read_uint16_array(&e, di->playback_formats, sizeof(di->playback_formats) / 2); + e += ptp_read_string2(e, di->extensions, sizeof(di->extensions)); + + e += ptp_read_u16(e, &di->functional_mode); - ptp_read_string(&e, di->manufacturer, sizeof(di->manufacturer)); - ptp_read_string(&e, di->model, sizeof(di->model)); + e += ptp_read_uint16_array2(e, di->ops_supported, sizeof(di->ops_supported) / 2, &di->ops_supported_length); + e += ptp_read_uint16_array2(e, di->events_supported, sizeof(di->events_supported) / 2, &di->events_supported_length); + e += ptp_read_uint16_array2(e, di->props_supported, sizeof(di->props_supported) / 2, &di->props_supported_length); + e += ptp_read_uint16_array2(e, di->capture_formats, sizeof(di->capture_formats) / 2, &di->capture_formats_length); + e += ptp_read_uint16_array2(e, di->playback_formats, sizeof(di->playback_formats) / 2, &di->playback_formats_length); - ptp_read_string(&e, di->device_version, sizeof(di->device_version)); - ptp_read_string(&e, di->serial_number, sizeof(di->serial_number)); + e += ptp_read_string2(e, di->manufacturer, sizeof(di->manufacturer)); + e += ptp_read_string2(e, di->model, sizeof(di->model)); - format_sane_string(di->manufacturer); - format_sane_string(di->model); - format_sane_string(di->device_version); - format_sane_string(di->serial_number); + e += ptp_read_string2(e, di->device_version, sizeof(di->device_version)); + e += ptp_read_string2(e, di->serial_number, sizeof(di->serial_number)); - r->di = di; + r->di = di; // set last parsed di return 0; } @@ -531,7 +517,7 @@ int ptp_fuji_parse_object_info(struct PtpRuntime *r, struct PtpFujiObjectInfo *o uint8_t *d = ptp_get_payload(r); memcpy(oi, d, PTP_FUJI_OBJ_INFO_VAR_START); d += PTP_FUJI_OBJ_INFO_VAR_START; - ptp_read_string(&d, oi->filename, sizeof(oi->filename)); + d += ptp_read_string2(d, oi->filename, sizeof(oi->filename)); /* TODO: Figure out payload later: 0D 44 00 53 00 43 00 46 00 35 00 30 00 38 00 37 00 2E 00 4A 00 50 00 47 00 diff --git a/src/operations.c b/src/operations.c index 9b94be8..9f52d94 100644 --- a/src/operations.c +++ b/src/operations.c @@ -205,8 +205,7 @@ int ptp_send_object_info(struct PtpRuntime *r, int storage_id, int handle, struc cmd.params[1] = handle; char temp[1024]; - void *temp_ptr = temp; - int length = ptp_pack_object_info(r, oi, &temp_ptr, sizeof(temp)); + int length = ptp_pack_object_info(r, oi, temp, sizeof(temp)); if (length == 0) { return PTP_OUT_OF_MEM; } diff --git a/src/packet.c b/src/packet.c index 5851c29..a50bae4 100644 --- a/src/packet.c +++ b/src/packet.c @@ -51,6 +51,8 @@ void ptp_read_string(void *dat, char *string, int max) { int y = 0; while (y < length) { string[y] = (char)ptp_read_uint8(dat); + if (string[y] < 0) string[y] = '?'; // TODO: utf16 -> utf8 + else if (string[y] != '\0' && string[y] < 32) string[y] = ' '; ptp_read_uint8(dat); // skip \0 y++; if (y >= max) { break; } @@ -59,6 +61,13 @@ void ptp_read_string(void *dat, char *string, int max) { string[y] = '\0'; } +// Read standard UTF16 string +int ptp_read_string2(uint8_t *dat, char *string, int max) { + uint8_t *two = dat; + ptp_read_string(&two, string, max); + return two - dat; +} + int ptp_read_uint16_array(void *dat, uint16_t *buf, int max) { int n = ptp_read_uint32(dat); @@ -73,6 +82,12 @@ int ptp_read_uint16_array(void *dat, uint16_t *buf, int max) { return n; } +int ptp_read_uint16_array2(uint8_t *dat, uint16_t *buf, int max, int *length) { + uint8_t *two = dat; + (*length) = ptp_read_uint16_array(&two, buf, max); + return two - dat; +} + int ptp_write_string(void *dat, char *string) { int length = strlen(string); ptp_write_uint8(dat, length); @@ -87,14 +102,22 @@ int ptp_write_string(void *dat, char *string) { return (length * 2) + 2; } +int ptp_write_string2(uint8_t *dat, char *string) { + uint8_t *old = dat; + return ptp_write_string(&dat, string); +} + int ptp_write_utf8_string(void *dat, char *string) { - for (int i = 0; string[i] != '\0'; i++) { - ptp_write_uint8(dat, string[i]); + char *o = (char *)dat; + int x = 0; + while (string[x] != '\0') { + o[x] = string[x]; + x++; } - ptp_write_uint8(dat, '\0'); - - return strlen(string) + 1; + o[x] = '\0'; + x++; + return x; } // Write null-terminated UTF16 string @@ -123,6 +146,7 @@ int ptp_read_unicode_string(char *buffer, char *dat, int max) { return i / 2; } +#if 0 // Read null terminated UTF8 string void ptp_read_utf8_string(void *dat, char *string, int max) { uint8_t **p = (uint8_t **)dat; @@ -138,6 +162,22 @@ void ptp_read_utf8_string(void *dat, char *string, int max) { (*p)++; string[y] = '\0'; } +#endif + +int ptp_read_utf8_string2(void *dat, char *string, int max) { + char *d = (char *)dat; + int x = 0; + while (d[x] != '\0') { + string[x] = d[x]; + x++; + if (x > max - 1) break; + } + + string[x] = '\0'; + x++; + + return x; +} // PTP/IP-specific packet int ptpip_bulk_packet(struct PtpRuntime *r, struct PtpCommand *cmd, int type) { diff --git a/test/test.c b/test/test.c index aa334e0..cc55081 100644 --- a/test/test.c +++ b/test/test.c @@ -57,6 +57,8 @@ int ptp_vcam_magic() { if (rc) return rc; } + //rc = ptp_eos_evproc_run(&r, "EnableBootDisk %d 'aasd'", 10); + ptp_close(&r); return 0; } @@ -149,6 +151,12 @@ int test_fs() { ptp_device_info_json(&di, buffer, sizeof(buffer)); printf("%s\n", buffer); + struct PtpDevPropDesc pd; + rc = ptp_get_prop_desc(&r, PTP_PC_BatteryLevel, &pd); + if (rc) return rc; + assert(pd.current_value == 50); + assert(pd.default_value == 50); + struct PtpArray *arr; rc = ptp_get_storage_ids(&r, &arr); if (rc) return rc; @@ -165,6 +173,13 @@ int test_fs() { ptp_storage_info_json(&si, buffer, sizeof(buffer)); printf("%s\n", buffer); +/* Not implemented in vcam! + struct PtpObjectInfo oi = {0}; + strcpy(oi.filename, "test.jpg"); + rc = ptp_send_object_info(&r, id, 0, &oi); + if (rc) return rc; +*/ + rc = ptp_get_object_handles(&r, id, 0, 0, &arr); if (rc) return rc; assert(ptp_get_return_code(&r) == PTP_RC_OK);