/*************************************************************************** * copyright : (C) 2002 by Hendrik Sattler * * mail : post@hendrik-sattler.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //own headers #include #include #include #include #include "ucs4.h" //standard headers #include #include #include #include #include static size_t replace_char_escape (char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { uint16_t temp = (uint16_t)(*((ucs4char_t*)*inbuf) & UINT16_MAX); if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL || *inbytesleft <= 0) { return 0; } if (*outbytesleft < 5) { return (size_t)-1; } /* do this endianess independent */ sprintf(*outbuf,"\\%02X%02X",(temp>>8)&0xFF,temp&0xFF); *inbuf += sizeof(ucs4char_t); *inbytesleft -= sizeof(ucs4char_t); *outbuf += 5; *outbytesleft -= 5; return 0; } static size_t replace_char_questionmark (char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL || *inbytesleft <= 0) { return 0; } if (*outbytesleft < 5) { return (size_t)-1; } sprintf(*outbuf,"?"); *inbuf += sizeof(ucs4char_t); *inbytesleft -= sizeof(ucs4char_t); *outbuf += 1; *outbytesleft -= 1; return 0; } static size_t replace_char(enum repmode replacement_mode, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { size_t retval = 0; switch(replacement_mode) { case REPMODE_IGNORE: fprintf(stderr,_("%s: Unicode character 0x%lx cannot be converted.\n"),_("Error"), (unsigned long)*((ucs4char_t*)*inbuf)); break; case REPMODE_ESCAPE_CHARS: retval = replace_char_escape(inbuf,inbytesleft,outbuf,outbytesleft); break; case REPMODE_QUESTIONMARK: retval = replace_char_questionmark(inbuf,inbytesleft,outbuf,outbytesleft); break; } return retval; } char* convert_from_internal (const char* to_code, ucs4char_t* input, enum repmode replacement_mode) { iconv_t cd; size_t status; int estatus; char* retval; size_t insize = sizeof(ucs4char_t); size_t insize_conv; char* inptr = (char*)input; char* inptr_conv = inptr; /* must be at least 5 for replace_char functions */ const size_t mult = (MB_LEN_MAX>5)?MB_LEN_MAX:5; /* this should be enough for every possible locale * MB_CUR_MAX can NOT be used! */ size_t outsize = ucs4len(input)*mult; size_t outsize_conv = outsize; char* outptr; char* outptr_conv; if (to_code == NULL || input == NULL) return NULL; cd = iconv_open(to_code,ucs4_get_iconv_charset()); if (cd == (iconv_t)-1) { fprintf(stderr,_("Error on text conversion from charset \"%s\" to charset \"%s\": %s\n"), ucs4_get_iconv_charset(),to_code,strerror(errno)); exit(EXIT_FAILURE); } retval = mem_alloc(outsize+mult,1); //not to be modified later outptr = retval; outptr_conv = retval; while (ucs4len((ucs4char_t*)inptr) > 0) { insize_conv = insize; status = iconv(cd, (ICONV_CAST)&inptr_conv,&insize_conv, &outptr_conv,&outsize_conv); estatus = errno; /* the character conversion may have failed * because the target charset has no such char */ if (status > (size_t)0) { insize_conv = insize; //set the vars back to before conversion try inptr_conv = inptr; outptr_conv = outptr; outsize_conv = outsize; status = replace_char(replacement_mode, &inptr_conv,&insize_conv, &outptr_conv,&outsize_conv); if (status == (size_t)-1) { //there is only one implemented estatus = E2BIG; } } /* the character conversion/replacement may be buggy */ if (status == (size_t)-1) { switch (estatus) { case E2BIG: //we have to resize outbuf, should never happen fprintf(stderr,"%s: %s %s\n",_("Error"), _("insufficient memory on unicode decoding."), _("Please report as bug.")); exit(EXIT_FAILURE); break; case EINVAL: case EILSEQ: fprintf(stderr,"%s: %s\n",_("Error with internal charset"),strerror(estatus)); exit(EXIT_FAILURE); break; default: fprintf(stderr,"%s: %s\n",_("Error"),strerror(estatus)); exit(EXIT_FAILURE); break; } } //we update the loop-external values, too inptr = inptr_conv; outptr = outptr_conv; outsize = outsize_conv; } iconv_close(cd); return retval; }