rewrote ucs-2 conversion to do endian conversiondireclty
git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@9964 67ed7778-7388-44ab-90cf-0a291f65f57c
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
2007-02-02 Marcus Meissner <marcus@jet.franken.de>
|
||||
|
||||
* library.c: Rewritten UCS-2 handling to not
|
||||
use strange hacks, but UCS-2LE directly.
|
||||
(from Chuck Cranor)
|
||||
|
||||
2007-01-29 Marcus Meissner <marcus@jet.franken.de>
|
||||
|
||||
* library.c: Added focuslock toggle option.
|
||||
|
||||
@@ -51,23 +51,6 @@
|
||||
# define N_(String) (String)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On MacOS (Darwin) and *BSD we're not using glibc, but libiconv.
|
||||
* glibc knows that UCS-2 is to be in the local machine endianness,
|
||||
* whereas libiconv does not. So we construct this macro to get
|
||||
* things right. Reportedly, glibc 2.1.3 has a bug so that UCS-2
|
||||
* is always bigendian though, we would need to work around that
|
||||
* too...
|
||||
*/
|
||||
#ifndef __GLIBC__
|
||||
#define UCS_2_INTERNAL "UCS-2-INTERNAL"
|
||||
#else
|
||||
#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 )
|
||||
#error "Too old glibc. This versions iconv() implementation cannot be trusted."
|
||||
#endif
|
||||
#define UCS_2_INTERNAL "UCS-2"
|
||||
#endif
|
||||
|
||||
#include "ptp.h"
|
||||
#include "ptp-bugs.h"
|
||||
#include "ptp-private.h"
|
||||
@@ -3861,7 +3844,7 @@ camera_init (Camera *camera, GPContext *context)
|
||||
CameraAbilities a;
|
||||
int ret, i, retried = 0;
|
||||
PTPParams *params;
|
||||
char *curloc;
|
||||
char *curloc, *camloc;
|
||||
GPPortSettings settings;
|
||||
|
||||
gp_port_get_settings (camera->port, &settings);
|
||||
@@ -3893,6 +3876,11 @@ camera_init (Camera *camera, GPContext *context)
|
||||
memset (camera->pl->params.data, 0, sizeof (PTPData));
|
||||
((PTPData *) camera->pl->params.data)->camera = camera;
|
||||
camera->pl->params.byteorder = PTP_DL_LE;
|
||||
if (camera->pl->params.byteorder == PTP_DL_LE)
|
||||
camloc = "UCS-2LE";
|
||||
else
|
||||
camloc = "UCS-2BE";
|
||||
|
||||
camera->pl->params.maxpacketsize = settings.usb.maxpacketsize;
|
||||
if (!camera->pl->params.maxpacketsize)
|
||||
camera->pl->params.maxpacketsize = 64; /* assume USB 1.0 */
|
||||
@@ -3933,8 +3921,8 @@ camera_init (Camera *camera, GPContext *context)
|
||||
|
||||
curloc = nl_langinfo (CODESET);
|
||||
if (!curloc) curloc="UTF-8";
|
||||
camera->pl->params.cd_ucs2_to_locale = iconv_open(curloc, UCS_2_INTERNAL);
|
||||
camera->pl->params.cd_locale_to_ucs2 = iconv_open(UCS_2_INTERNAL, curloc);
|
||||
camera->pl->params.cd_ucs2_to_locale = iconv_open(curloc, camloc);
|
||||
camera->pl->params.cd_locale_to_ucs2 = iconv_open(camloc, curloc);
|
||||
if ((camera->pl->params.cd_ucs2_to_locale == (iconv_t) -1) ||
|
||||
(camera->pl->params.cd_locale_to_ucs2 == (iconv_t) -1)) {
|
||||
gp_log (GP_LOG_ERROR, "iconv", "Failed to create iconv converter.\n");
|
||||
|
||||
@@ -89,50 +89,46 @@ dtoh64ap (PTPParams *params, unsigned char *a)
|
||||
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) {
|
||||
int i;
|
||||
/* try the old way, in case iconv is broken */
|
||||
for (i=0;i<loclen;i++) {
|
||||
if (string[i]>127)
|
||||
loclstr[i] = '?';
|
||||
else
|
||||
loclstr[i] = string[i];
|
||||
}
|
||||
string[loclen] = 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -147,7 +143,6 @@ ucs2strlen(uint16_t const * const unicstr)
|
||||
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;
|
||||
@@ -157,11 +152,15 @@ ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t o
|
||||
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;
|
||||
@@ -170,10 +169,8 @@ ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t o
|
||||
|
||||
/* 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;
|
||||
|
||||
Reference in New Issue
Block a user