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:
Marcus Meissner
2007-02-02 09:32:29 +00:00
parent 4987871b39
commit 2fda09bd42
3 changed files with 58 additions and 67 deletions

View File

@@ -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.

View File

@@ -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");

View File

@@ -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;