| /** | |
| *** Transcoding support and wrappers. | |
| *** | |
| *** See Copyright for the status of this software. | |
| *** | |
| *** Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A. | |
| **/ | |
| #define IN_LIBXML | |
| #include "libxml.h" | |
| #include <sys/types.h> | |
| #include <iconv.h> | |
| #include "libxml/xmlmemory.h" | |
| #include "libxml/dict.h" | |
| #include "transcode.h" | |
| /** | |
| *** Destroy a dictionary and mark as destroyed. | |
| **/ | |
| void | |
| xmlZapDict(xmlDictPtr * dict) | |
| { | |
| if (dict && *dict) { | |
| xmlDictFree(*dict); | |
| *dict = (xmlDictPtr) NULL; | |
| } | |
| } | |
| /** | |
| *** Support for inline conversion from/to UTF-8. | |
| *** This is targetted to function parameter encoding conversion. | |
| *** Method is: | |
| *** - Convert string from/to UTF-8. | |
| *** - Keep it in a dictionary. | |
| *** - Free original string if a release procedure is provided. | |
| *** Can also be called without dictionary to convert a string from/to UTF-8 | |
| *** into xmlMalloc'ed dynamic storage. | |
| **/ | |
| const char * | |
| xmlTranscodeResult(const xmlChar * s, const char * encoding, | |
| xmlDictPtr * dict, void (*freeproc)(const void *)) | |
| { | |
| size_t l; | |
| iconv_t cd; | |
| char * srcp; | |
| char * dstp; | |
| size_t srcc; | |
| size_t dstc; | |
| char * ts; | |
| const char * ret; | |
| int err; | |
| static const int nullstring[] = { 0 }; | |
| /* Convert from UTF-8. */ | |
| if (!s) | |
| return (const char *) NULL; | |
| ret = (const char *) NULL; | |
| ts = (char *) NULL; | |
| err = 0; | |
| l = xmlStrlen(s); | |
| if (!l && dict) | |
| ret = (const char *) nullstring; | |
| else { | |
| if (dict && !*dict) | |
| err = !(*dict = xmlDictCreate()); | |
| if (!err) | |
| err = !(ts = xmlMalloc(4 * l + 4)); | |
| dstp = ts; | |
| dstc = 4 * l; | |
| if (!err && l) { | |
| if (!encoding) | |
| encoding = "ibm-0"; /* Job's encoding. */ | |
| cd = iconv_open(encoding, "UTF-8"); | |
| if (cd == (iconv_t) -1) | |
| err = 1; | |
| else { | |
| srcp = (char *) s; | |
| srcc = l; | |
| srcc = iconv(cd, &srcp, &srcc, &dstp, &dstc); | |
| iconv_close(cd); | |
| err = srcc == (size_t) -1; | |
| } | |
| } | |
| if (!err) { | |
| dstp[0] = dstp[1] = dstp[2] = dstp[3] = '\0'; | |
| if (!dict) { | |
| if (dstc) | |
| ts = xmlRealloc(ts, (dstp - ts) + 4); | |
| ret = (const char *) ts; | |
| ts = (char *) NULL; | |
| } | |
| else | |
| ret = (char *) xmlDictLookup(*dict, | |
| (xmlChar *) ts, dstp - ts + 1); | |
| } | |
| } | |
| if (ts) | |
| xmlFree(ts); | |
| if (freeproc) | |
| (*freeproc)(s); | |
| return ret; | |
| } | |
| /** | |
| *** Support for inline conversion to UTF-8. | |
| *** Method is: | |
| *** - Convert string to UTF-8. | |
| *** - Keep it in a dictionary. | |
| *** Can also be called without dictionary to convert a string to UTF-8 into | |
| *** xmlMalloc'ed dynamic storage. | |
| **/ | |
| static const xmlChar * | |
| inTranscode(const char * s, size_t l, const char * encoding, xmlDictPtr * dict) | |
| { | |
| iconv_t cd; | |
| char * srcp; | |
| char * dstp; | |
| size_t srcc; | |
| size_t dstc; | |
| xmlChar * ts; | |
| const xmlChar * ret; | |
| static const xmlChar nullstring[] = { 0 }; | |
| if (!l && dict) | |
| return nullstring; | |
| if (dict && !*dict) | |
| if (!(*dict = xmlDictCreate())) | |
| return (const xmlChar *) NULL; | |
| ts = (xmlChar *) xmlMalloc(6 * l + 1); | |
| if (!ts) | |
| return (const xmlChar *) NULL; | |
| dstp = (char *) ts; | |
| dstc = 6 * l; | |
| if (l) { | |
| if (!encoding) | |
| encoding = "ibm-0"; /* Use job's encoding. */ | |
| cd = iconv_open("UTF-8", encoding); | |
| if (cd == (iconv_t) -1) { | |
| xmlFree((char *) ts); | |
| return (const xmlChar *) NULL; | |
| } | |
| srcp = (char *) s; | |
| srcc = l; | |
| srcc = iconv(cd, &srcp, &srcc, &dstp, &dstc); | |
| iconv_close(cd); | |
| if (srcc == (size_t) -1) { | |
| xmlFree((char *) ts); | |
| return (const xmlChar *) NULL; | |
| } | |
| } | |
| *dstp = '\0'; | |
| if (!dict) { | |
| if (dstc) | |
| ts = xmlRealloc(ts, (dstp - ts) + 1); | |
| return ts; | |
| } | |
| ret = xmlDictLookup(*dict, ts, dstp - ts + 1); | |
| xmlFree((char *) ts); | |
| return ret; | |
| } | |
| /** | |
| *** Input 8-bit character string parameter. | |
| **/ | |
| const xmlChar * | |
| xmlTranscodeString(const char * s, const char * encoding, xmlDictPtr * dict) | |
| { | |
| if (!s) | |
| return (const xmlChar *) NULL; | |
| return inTranscode(s, xmlStrlen(s), encoding, dict); | |
| } | |
| /** | |
| *** Input 16-bit character string parameter. | |
| **/ | |
| const xmlChar * | |
| xmlTranscodeWString(const char * s, const char * encoding, xmlDictPtr * dict) | |
| { | |
| size_t i; | |
| if (!s) | |
| return (const xmlChar *) NULL; | |
| for (i = 0; s[i] && s[i + 1]; i += 2) | |
| ; | |
| return inTranscode(s, i, encoding, dict); | |
| } | |
| /** | |
| *** Input 32-bit character string parameter. | |
| **/ | |
| const xmlChar * | |
| xmlTranscodeHString(const char * s, const char * encoding, xmlDictPtr * dict) | |
| { | |
| size_t i; | |
| if (!s) | |
| return (const xmlChar *) NULL; | |
| for (i = 0; s[i] && s[i + 1] && s[i + 2] && s[i + 3]; i += 4) | |
| ; | |
| return inTranscode(s, i, encoding, dict); | |
| } | |
| /** | |
| *** vasprintf() implementation with result transcoding. | |
| **/ | |
| const char * | |
| xmlVasprintf(xmlDictPtr * dict, const char * encoding, | |
| const xmlChar * fmt, va_list args) | |
| { | |
| char * s = NULL; | |
| vasprintf(&s, fmt, args); | |
| return xmlTranscodeResult((const xmlChar *) s, encoding, dict, free); | |
| } |