Sync in upstream libgphoto2
diff --git a/src/ptp-pack.c b/src/ptp-pack.c
index 8513a03..7efa66f 100644
--- a/src/ptp-pack.c
+++ b/src/ptp-pack.c
@@ -89,41 +89,46 @@
static inline char*
ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
{
- int i;
- uint8_t loclen;
+ uint8_t length;
+ uint16_t string[PTP_MAXSTRLEN+1];
+ /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
+ char loclstr[PTP_MAXSTRLEN*3+1];
+ size_t nconv, srclen, destlen;
+ char *src, *dest;
- /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
- loclen = dtoh8a(&data[offset]);
- /* This len is used to advance the buffer pointer */
- *len = loclen;
- if (loclen) {
- uint16_t string[PTP_MAXSTRLEN+1];
- char *stringp = (char *) string;
- char loclstr[PTP_MAXSTRLEN*3+1]; /* UTF-8 encoding is max 3 bytes per UCS2 char. */
- char *locp = loclstr;
- size_t nconv;
- size_t convlen = loclen * 2; /* UCS-2 is 16 bit wide */
- size_t convmax = PTP_MAXSTRLEN*3;
-
- for (i=0;i<loclen;i++) {
- string[i]=dtoh16a(&data[offset+i*2+1]);
+ length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
+ *len = length;
+ if (length == 0) /* nothing to do? */
+ return(NULL);
+
+ /* copy to string[] to ensure correct alignment for iconv(3) */
+ memcpy(string, &data[offset+1], length * sizeof(string[0]));
+ string[length] = 0x0000U; /* be paranoid! add a terminator. */
+ loclstr[0] = '\0';
+
+ /* convert from camera UCS-2 to our locale */
+ src = (char *)string;
+ srclen = length * sizeof(string[0]);
+ dest = loclstr;
+ destlen = sizeof(loclstr)-1;
+ nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen,
+ &dest, &destlen);
+ if (nconv == (size_t) -1) { /* do it the hard way */
+ int i;
+ /* try the old way, in case iconv is broken */
+ for (i=0;i<length;i++) {
+ if (dtoh16a(&data[offset+1+2*i])>127)
+ loclstr[i] = '?';
+ else
+ loclstr[i] = dtoh16a(&data[offset+1+2*i]);
}
- /* be paranoid! Add a terminator. :( */
- string[loclen]=0x0000U;
- loclstr[0]='\0';
- /* loclstr=ucs2_to_utf8(string); */
- /* Do the conversion. */
- nconv = iconv (params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax);
- /* FIXME: handle size errors */
- loclstr[PTP_MAXSTRLEN*3] = '\0';
- if (nconv == (size_t) -1)
- return NULL;
- return strdup(loclstr);
+ dest = loclstr+length;
}
- return NULL;
+ *dest = '\0';
+ loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
+ return(strdup(loclstr));
}
-
static inline int
ucs2strlen(uint16_t const * const unicstr)
{
@@ -138,7 +143,6 @@
static inline void
ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
{
- int i;
int packedlen;
uint16_t ucs2str[PTP_MAXSTRLEN+1];
char *ucs2strp = (char *) ucs2str;
@@ -148,11 +152,15 @@
size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
/* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
- ucs2str[0] = 0x0000U;
- memset(ucs2strp, 0, PTP_MAXSTRLEN*2+2);
- nconv = iconv (params->cd_locale_to_ucs2, &stringp, &convlen, &ucs2strp, &convmax);
+ memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
+ nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
+ &ucs2strp, &convmax);
if (nconv == (size_t) -1)
ucs2str[0] = 0x0000U;
+ /*
+ * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
+ * why do we need ucs2strlen()?
+ */
packedlen = ucs2strlen(ucs2str);
if (packedlen > PTP_MAXSTRLEN-1) {
*len=0;
@@ -161,10 +169,8 @@
/* number of characters including terminating 0 (PTP standard confirmed) */
htod8a(&data[offset],packedlen+1);
- for (i=0;i<packedlen && i< PTP_MAXSTRLEN; i++) {
- htod16a(&data[offset+i*2+1],ucs2str[i]);
- }
- htod16a(&data[offset+i*2+1],0x0000);
+ memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
+ htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
/* The returned length is in number of characters */
*len = (uint8_t) packedlen+1;
@@ -294,6 +300,20 @@
PTP_di_OperationsSupported+totallen,
&len);
}
+
+static void
+ptp_free_DI (PTPDeviceInfo *di) {
+ if (di->SerialNumber) free (di->SerialNumber);
+ if (di->DeviceVersion) free (di->DeviceVersion);
+ if (di->Model) free (di->Model);
+ if (di->Manufacturer) free (di->Manufacturer);
+ if (di->ImageFormats) free (di->ImageFormats);
+ if (di->CaptureFormats) free (di->CaptureFormats);
+ if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
+ if (di->OperationsSupported) free (di->OperationsSupported);
+ if (di->EventsSupported) free (di->EventsSupported);
+ if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
+}
/* ObjectHandles array pack/unpack */